Get computed property and pass its value while editing another text field vue.js - forms

I want to send over a computed property at the same time as editing a textfield so there is no button to "save" however I cannot work out how to get the property value from another field or from the computed data to pass over.
Here is my code so far, activeNote.id can be viewed in the template no problem but I want to pass its value whenever I type into the textarea
<template>
<div class="editor">
<form id="editForm">
<h2>Edit</h2>
<button #click="closeEdit()">Close</button>
<textarea
v-bind:value="activeNote.text"
#input="editNote"
class="form-control"
></textarea>
<input v-bind:value="activeNote.id" name="id" readonly />
</form>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
methods: {
// not sure this is best practice to dispatch from here
editNote(e) {
this.$store.dispatch('editNote', e)
// activeNote.id doesnt work here unfortunatly
this.$store.dispatch('noteId', activeNote.id)
//console.log(activeNote.id)
}
closeEdit() {
//console.log('emitclose')
this.$emit('closeEdit')
}
},
computed: mapState({
activeNote: state => state.activeNote
})
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

It was simple in the end so fyi the changed code that worked, adding this.
<template>
<div class="editor">
<form id="editForm">
<h2>Edit</h2>
<button #click="closeEdit()">Close</button>
<textarea
v-model="activeNote.text"
#input="editNote"
class="form-control"
></textarea>
<input v-bind:value="activeNote.id" name="id" readonly />
</form>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
methods: {
editNote(e) {
this.$store.dispatch('editNote', e)
this.$store.dispatch('noteId', this.activeNote.id)
},
closeEdit() {
this.$emit('closeEdit')
}
},
computed: mapState({
activeNote: state => state.activeNote
})
}
</script>

Related

How to disable autocomplete with v-form

I want to disable chrome autocomplete in my v-form. How do I do that? I don't see a autocomplete property on the v-form.
https://next.vuetifyjs.com/en/api/v-form/
While it is a property on a normal html form
https://www.w3schools.com/tags/att_form_autocomplete.asp
By setting autocomplete="username" and autocomplete="new-password" on v-text-field you can actually turn off the autocomplete in chrome.
here is a code that worked for me:
<v-form lazy-validation ref="login" v-model="validForm" #submit.prevent="submit()">
<v-text-field
v-model="user.email"
label="Email"
autocomplete="username"
/>
<v-text-field
v-model="user.password"
label="Password"
type="password"
autocomplete="new-password"
/>
<v-btn type="submit" />
</v-form>
Edit: autocomplete isn't set as a prop in vuetify docs but if you pass something to a component which isn't defined as prop in that component, it will accept it as an attribute and you can access it through $attrs.
here is the result of the above code in vue dev tools:
and here is the rendered html:
I wasn't able to get autofill disabled with the above methods, but changing the name to a random string/number worked.
name:"Math.random()"
https://github.com/vuetifyjs/vuetify/issues/2792
use autocomplete="off" in <v-text-field
<v-text-field
autocomplete="off"
/>
Just add:
autocomplete="false"
to your <v-text-field> or any input
autocomplete="null"
This one prevents Chrome autofill feature
I have not been able to get any of the previous proposals to work for me, what I finally did is change the text-flied for a text-area of a single line and thus it no longer autocompletes
Try passing the type='search' and autocomplete="off" props.
I also ran into a similar problem. Nothing worked until I found this wonderful Blog "How to prevent Chrome from auto-filling on Vue?" by İbrahim Turan
The main catch is that we will change the type of v-text-field on runtime. From the below code you can see that the type of password field is assigned from the value fieldTypes.password. Based on focus and blur events we assign the type of the field. Also, the name attribute is important as we decide based on that in the handleType() function.
I'm also pasting the solution here:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template>
<div id="app">
<div v-if="isloggedin" class="welcome">
Welcome {{username}}
</div>
<div v-else id="form-wrapper">
<label for="username">Username: </label>
<input
v-model="username"
class="form-input"
type="text"
name="username"
value=""
autocomplete="off"
/>
<label for="password">Password: </label>
<input
v-model="password"
class="form-input"
:type="fieldTypes.password"
name="password"
value=""
#focus="handleType"
#blur="handleType"
autocomplete="off"
/>
<button class="block" type="button" #click="saveCredentials">
Submit Form
</button>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
username: '',
password: '',
isloggedin: false,
fieldTypes: {
password: 'text',
}
}
},
methods: {
saveCredentials() {
this.isloggedin = true;
},
handleType(event) {
const { srcElement, type } = event;
const { name, value } = srcElement;
if(type === 'blur' && !value) {
this.fieldTypes[name] = 'text'
} else {
this.fieldTypes[name] = 'password'
}
}
}
}
</script>

Vue reactive forms components communication

I have multiple form components, each form as a component. Now, I want to use same component for adding data and editing data. So what I am thinking to do is something like when the Post component receives a prop containing data that means it is in a "editing mode" and populate the fields with its data, if not it is in "create mode".
So how should I use v-model in my form fields?
Should I v-model each form field to a computed property (which has a getter and a setter) and the computed property would check if the data prop is empty and if not use its data to populate fields ? And in the computed property set method to update the prop ?
parent component
<post :data.sync="dataObject"></post>
child (Post) component
<template>
<div>
<form>
<input type="text" label="title" v-model="computedTitle" />
<input type="text" label="message" v-model="computedMessage" />
</form>
</div>
<input type="button" #click="submitted"
<template>
<script>
export default {
data(){
return{
post:{
title:null,
message:null
}
}
},
props:["data"],
computed:{
computedTitle:{
get(){
return data ? data.title : ''
},
set(computedTitle){
computedTitle = computedTitle // trying to update computed property value with the field value...
}
},
computedMessage:{...}
}
}
</script>
You can use watch to check data prop, if it's set then set to local post variable.
If created, then data is null, post.title and post.message are set to null
If updated, then data is not null, post.title is set to data.title and post.message to set to data.message
<template>
<div>
<form>
<input type="text" label="title" v-model="post.title" />
<input type="text" label="message" v-model="post.message" />
</form>
</div>
<input type="button" #click="submitted"
<template>
<script>
export default {
data() {
return{
post: {
title: null,
message: null
}
}
},
props:["data"],
watch: {
data: {
handler(newData) {
if (newData) {
this.post = {
title: newData.title,
message: newData.message
}
}
},
immediate: true // this makes watch is called when component created
}
}
}
</script>
Note that you should use immediate: true to make the watch's function called when component is created

react rerendering form causes focus/blur issue on state change

I have a form in a react component that has two change handlers, one for my two draftjs textareas, and one for my other text inputs:
onChangeEditor = (editorStateKey) => (editorState) => {
this.setState({ [editorStateKey]: editorState });
}
handleInputChange(event) {
event.preventDefault();
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
In my render method I have two views that I switch between depending on which view mode I am in, read or edit:
render () {
const Editable = () => (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" key="text01" name="title" defaultValue={this.state.title} onBlur={this.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.state.editorState1} onChange={this.onChangeEditor('editorState1')} name="text01"/>
<h4>Citat</h4>
<input type="text" key="text02" name="quote01" defaultValue={this.state.quote01} onBlur={this.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.state.editorState2} onChange={this.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.saveForm} />
</form>
</div>
);
const Readable = () => (
<div>
<h1 className="header66">{this.state.title}</h1>
<div className="text66">{this.state.text01}</div>
<div className="quote100">{this.state.quote01}</div>
<div className="text66">{this.state.text02}</div>
</div>
);
return (
<div>
{ this.props.isInEditMode ? <Editable /> : <Readable /> }
</div>
);
}
When I switch between inputs in my browser I have to click twice in order to get the focus on the right input.
I suspect that this is because a change is triggered on the "blur" event of each input, causing the form to rerender because state is changed. And when the form rerenders, it goes through the { this.props.isInEditMode ? <Editable /> : <Readable /> } which causes the input to lose focus.
The problem is that I don't know how to get around this.
I solved it myself.
It turns out that it was not a good idea to place the Editable and Readable inside of my component as I did. Instead I moved them out to their own components, and it works properly now.
class Editable extends React.Component {
render() {
return (
<div className="editor">
<form className="editor-inner">
<h3>Redigerar: Anbudsbrev</h3>
<h4>Rubrik</h4>
<input type="text" name="title" defaultValue={this.props.title} onChange={this.props.handleInputChange} />
<h4>Text 1</h4>
<RichEditor editorState={this.props.editorState1} onChange={this.props.onChangeEditor('editorState1')} name="text01" />
<h4>Citat</h4>
<input type="text" name="quote01" defaultValue={this.props.quote01} onChange={this.props.handleInputChange} />
<h4>Text 2</h4>
<RichEditor editorState={this.props.editorState2} onChange={this.props.onChangeEditor('editorState2')} name="text02" />
<EditorFooter {...this.props} submitForm={this.props.saveForm} />
</form>
</div>
);
}
};
class Readable extends React.Component {
render() {
return (
<div>
<h1 className="header66">{this.props.title}</h1>
<div className="text66">{this.props.text01}</div>
<div className="quote100">{this.props.quote01}</div>
<div className="text66">{this.props.text02}</div>
</div>
);
}
};

In Redux, how to get user input

I have a form, how to get the use input in the handleSubmit() method?
handleSubmit(e) {
e.preventDefault()
//how to get the user input?
}
render() {
return (
<div className="col-sm-4">
<form onSubmit={this.handleSubmit}>
<input type="text" placeholder="user"/>
<input type="text" placeholder="comments"/>
<input type="submit" hidden/>
</form>
</div>
)
}
so far, I know three solutions:
The first one, use refs, but I can see there are lots of people saying that we should avoid using it
The second one, add onChange() to each <input>, e.g.
class Example extends React.Component {
state = {
inputValue: ""
};
handleInputChanged(e) {
this.setState({
inputValue: e.target.value
});
}
render() {
return (
<div>
<input onChange={this.handleInputChanged.bind(this)} value={this.state.inputValue}>
</div>
);
}
}
this one is fine with a few inputs. But if the form has 20 input fields, then there are 20 different onChange methods?
third, use some npm module, like redux-form.
any other suggestion? Thanks
You can actually just do an onChange on the parent form like so:
onChange(e) {
switch(e.target.type) {
case 'checkbox':
this.setState({ [e.target.name]: e.target.checked });
break;
default:
this.setState({ [e.target.name]: e.target.value });
break;
}
}
// in render
<form onChange={this.onChange.bind(this)}>
<input name="foo1" />
<input name="foo2" />
<input name="foo3" />
<input name="foo4" />
<input name="foo5" />
<input name="foo6" />
<input name="foo7" />
<input name="foo8" />
</form>
There are certain libraries like https://github.com/christianalfoni/formsy-react, https://github.com/prometheusresearch/react-forms. These forms have additional functions pre written for form submitting, validations. I think using refs is a tedious and unwanted task if the form is big with the reason being that if it is controlled form you need to access the state value for controlled components which brings unnecessary complications. You can do it but it is better to use prewritten libraries.

Why doesn't my React Js form accept user input?

I have a simple AddUser component and in the render function I am returning the following html:
<form ref="form" className="users-form" onSubmit={ this.handleAddNew }>
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={function() {}} /><br />
<input ref="email" type="email" name="email" placeholder="email"
value={this.state.email} onChange={function() {}} /><br />
<button type="submit"> Add User </button>
</form>
I am binding the state of username and email to this.state which I am setting to blank in getInitialState like so:
getInitialState() {
return { username: '', email: '' };
}
I am binding state to the form so I can set it to blank after form submission.
The problem with this setup is that the form now renders as readonly.
I cannot get any user input into either text fields. What am I doing wrong?
Your input fields are controlled components, since you are using the value property. This makes the inputs readonly and they will always reflect the value, the variable (in this case, the state variable) holds. You have to explicitly setState onChange since you are setting username field as a state variable.
Read more about it here
onUserNameChange : function(e){
this.setState({username : e.target.value})
},
render: function(){
return ...
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={this.onUserNameChange} /><br />
...
<button type="submit"> Add User </button>
</form>
}
A better way to do this is :
onChange : function(field,e){
this.setState({field: e.target.value});
},
render : function(){
return <form ref="form" className="users-form" onSubmit={ this.handleAddNew }>
<input ref="username" type="text" name="username" placeholder="username"
value={this.state.username} onChange={this.onChange.bind(this,"username")} /><br />
<input ref="email" type="email" name="email" placeholder="email"
value={this.state.email} onChange={this.onChange.bind(this,"email")} /><br />
<button type="submit"> Add User </button>
</form>
}
It looks like you saw the console warning about controlled fields needing an onChange handler and added one just to shut the warning up :)
If you replace your empty onChange handler functions with onChange={this.handleChange} and add this method to your component, it should work:
handleChange(e) {
this.setState({[e.target.name]: e.target.value})
}
(Or for people not using an ES6 transpiler:)
handleChange: function(e) {
var stateChange = {}
stateChange[e.target.name] = e.target.value
this.setState(stateChange)
}
However, if your component is an ES6 class extending React.Component (instead of using React.createClass()), you will also need to ensure the method is bound to the component instance properly, either in render()...
onChange={this.handleChange.bind(this)}
...or in the constructor:
constructor(props) {
super(props)
// ...
this.handleChange = this.handleChange.bind(this)
}