Vue 3 - Emitting primitive value doesn't trigger input? - javascript

I faced an strange issue with Vue3 $emit. I was refactoring my own Vue2 "form-input" -component, which is basically an wrapper for rendering either text-input, (multi)select-option, textarea or any other basic input field.
This component used to bind value against v-model, so it was emitting input via "this.$emit('input', this.value)".
Since Vue 3 changed input to update:modelValue, I made this modification and additionally presented "Emits" -property-list to component. Everything was seemingly working...
But then I recognized that Vue-multiselect 3 (NPM package "vue-multiselect": "^3.0.0-alpha.2") was emitting primitive value, an integer number, which didn't trigger #input on parent-component.
form-input.vue
<input v-if="resolveType === 'text' || resolveType === 'number' || resolveType === 'tel' || resolveType === 'email'"
v-model="localValue"
#input="$emit('update:modelValue', $event.target.value)"
/>
<multiselect v-model="localValue"
class="full-width-tags"
#update:model-value="$emit('update:modelValue', $event)"
/>
// Please note that multiselects $event is an integer, I have checked this multiple times from console.log
... and when I'm listening for #input on parent component it seems "text"-type field triggers event-listener but multiselect doesn't. Only difference on these components is that multiselect is emitting primitive value (integer), while input is sending an event-object.
Could someone explain why event-object and primitive value are handled differently for #input , and how could I fix my multiselects emit so that it's emitting input? Currently I'm emitting both "update:modelValue" AND "input" -events one after another for multiselect, but I'm just wondering if there is easier way?

From your question it seems you have read the Vue 3 Migration Guide - particularly the part about change of v-model on custom components and changed your form-input to emit update:modelValue event instead of input event
So why are you listening for updates on your form-input component with #input instead of #update:modelValue ?
The only reason why the #input placed on your form-input component in the parent works, is because of this change
In short - because your component declares that it emits update:modelValue event (using emits option), every other event listener placed on it is directly bound to the root element of the component - native <input> in this case
This is not what you want. Just change <form-input #input="..." /> to <form-input #update:modelValue="..." />

Related

Getting v-model from a quasar file picker field

In a vue app using quasar, I have three file picker fields, and when one of those fields change, I want to call a specific function. I want to be able to pass the v-model as a variable into the function so I can update the v-model using the function.
See more problem description in the onSelected function description.
For example, I may want to bind the v-model of whatever field was changed to a new variable. So how would I tell the function what v-model was passed at the #change event?
<q-file
v-model="fieldOne"
#change="onSelected()"
></q-file>
<q-file
v-model="fieldTwo"
#change="onSelected()"
></q-file>
<q-file
v-model="fieldThree"
#change="onSelected()"
></q-file>
function onSelected(event) {
// I would like to update the v-model of the field that was
// subject to the #change event. event.target.value doesn't
// work. How to I work with the specific v-model that
// triggered
//the #change event?
}

getting error React does not recognize the `handleChange` prop on a DOM element

I am trying to make one login form in react .but I am getting this error
React does not recognize the handleChange prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase handlechange instead.
input value is also not setting input field when I type in input field it is not updating the state why ?
here is my code
https://codesandbox.io/s/quirky-clarke-qbkjw
<form noValidate>
<TextBox
label="Username"
name="username"
type="text"
helperText="Assistive text"
handleChange={handleChange}
handleMouseDownPassword={handleMouseDownPassword}
value={userId}
/>
<TextBox
label="Password"
name="password"
type="password"
helperText="Assistive text"
value={password}
showPassword={showPassword}
handleChange={handleChange}
handleClickShowPassword={handleClickShowPassword}
handleMouseDownPassword={handleMouseDownPassword}
/>
<div className="button-group">
<button>LOGIN</button>
</div>
</form>
In the TextBox component you're passing all the props from the parent via {...props}. Considering that TextField itself doesn't have handleChange property, I assume it passes it down to the underlying input DOM element, which doesn't recognise that prop.
What you can do is to extract the props used inside TextBox and collect the rest using the rest argument, so you don't end up passing unnecessary props down:
export default function TextBox({handleChange, handleClickShowPassword, handleMouseDownPassword, value, ...props}) {
Another option is to remove {...props} from the TextField component and explicitly pass all the necessary props.
Updated Sandbox
React doesn't like uppercase letters in the prop names. Instead of passing "handleChange", pass "handlechange". You will get a similar error for "handleMouseDownPassword".
Regarding the input issue, I don't think you've provided enough context. But you have to have a handleChange method to update the state each time the field is changed.
I changed the handleChange() function, you were only setting the VALUE state, you need to set the state userId when you write on the first input, and the password when you write to the second input
At b.js add props name={stateName} so the handleChange() can know which input is controlling
Check Demo for more:
https://codesandbox.io/s/gracious-heisenberg-z4q4z
(other answeres explained why you are getting that error in console ...props)

Javascript Vue Event Emit Not Value

Good Evening,
does anyone know why the input toggle switch value is being flipped to the reverse value when emitted to the parent component? I'm new to Vue, I have been working with it on and off for a few days now. It works in concept, I can see the value of the attribute in both areas using vue dev tools. However, the child value is reversed when emitted to the parent and assigned. I could immediately fix by !'ing the incoming value, but I would like to find out if anyone knows why this is occurring.
Parent Update Bind
updateMiddle(article){
this.article.meta_title = article.meta_title;
this.article.meta_desc = article.meta_desc;
this.article.published = article.published;
this.article.is_review = article.is_review;
}
Child Emit
methods: {
update() {
this.$emit('changeMiddle',this.article)
}
Input
<input id="tc-review" type="checkbox" hidden="hidden" name="is_review"
v-model="article.is_review" v-on:input="update">
The problem is that the input event fires before the v-model binding has changed the data.
Simple solution is to use the change event instead. For example
<input v-model="article.is_review" #change="update">
Simplified demo ~ http://jsfiddle.net/u20h5tzv/
Hint: Try changing it back to #input and see the difference in timing.

React: Have to constantly update state to make textarea editable

In my component, I render this textarea:
<textarea id="descript" rows="8" value={this.state.description} />
and I was surprised to find that I couldn't type in it. After some experimentation, I found that I was typing it in, but react was just reseting the value every time I typed a character to the state variable. So, I've gotten it to let me type by adding this onChange:
<textarea id="descript" rows="8" value={this.state.description}
onChange={() => {this.textChanged();}} />
and this is the handler:
textChanged(event) {
var newDesc = document.getElementById('descript').value;
this.setState({'description':newDesc});
}
This works, but it's an incredibly expensive way to have React not do anything. Is there a better/right way to approach this that will just let me edit the textarea? For example, with the input fields in the form, I just use defaultValue instead, but I need this one to be multiple lines.
The way you are trying is okay. Just need a little tweak. Try this:
<textarea
id="descript"
rows="8"
value={this.state.description}
onChange={this.textChanged}
/>
textChanged(event) {
this.setState({
description: event.target.value
});
}
And don't forget to bind the function in your constructor like this:
this.textChanged= this.textChanged.bind(this);
As you are using it as a controlled component so the state will always be reflected in the textarea's value.
In React, this is called a controlled-component. Since you're setting your <textarea>'s value to this.state.description, the <textarea> will always reflect this, making the React state the source of truth. As a result you must also handle changes. You may be falling victim to premature optimization, this is generally very fast, and is a best practice. In React, your component rendering should be predicable based on your state and props.
As Arslan mentioned, however, since your handler receives event just the same as a normal onChange handler, a simpler way to do this is simply to set your state to event.target.value rather than grabbing a reference to your <textarea> and getting it's value.
Is there a reason why the textarea contents need to be in the state?
You can use another variable (or a property passed into the component) instead:
<textarea id="descript" rows="8" value={description} />
or
<textarea id="descript" rows="8" value={this.props.description} />
Then instead of an onChange handler, you read the updated value of the textarea when you are ready to use it.
You are using the as a controlled component, where the value it holds will always be this.state.description. You are right that when used this way you will need supply an onChange function but you do not need to set an id and use the document API.
You can read more about it here: https://reactjs.org/docs/forms.html#controlled-components
You do not need to use it as a controlled component. If you don't set the value prop you will be able to type as is. Then when you wish to capture that value you can read the value from the textarea element either by ref or by id.

Detecting changes to an input value - vue2

I am using a date time picker component for vue2. While it renders nicely and seem to function well with basic usage, I am not able to detect changes to the input value within the vue component. I tried adding #change to the component instance, although it never seems to fire. Any idea why this is? Note, v-model updates the value of cool successfully.
Vue Methods
export default {
...
methods: {
someEvent() {
alert("SUCCESS"); //this never fires
}
Vue Markup
<date-picker
v-model="cool"
lang="en"
type="datetime"
input-class="date-time-picker"
format="MM/DD/YYYY hh:mm A"
#change="someEvent()"
:confirm="true"
>
</date-picker>
JsFiddle:
https://jsfiddle.net/aw5g3q9x/
When you add an event listener to a component tag (such as #change="someEvent()"), Vue will listen for a custom event to be emitted from the component. The <date-picker> component never emits a custom change event. Looking at the documentation, it appears that it only ever emits a confirm event when the optional "OK" button is pressed.
Your best option is to set a watcher on the cool property to fire the someEvent method whenever the value of cool changes:
watch: {
cool() {
this.someEvent();
}
}
For future reference, if the root element of the component was an input, you could use the .native modifier to listen for the change DOM event of that input element like so #change.native="someEvent()". However, the root element of the <date-picker> component is a div, so that wouldn't work in this case.
I do not know the datepicker, but in your case you can use variable change watcher
Vue.use(window.DatePicker.default)
new Vue({
el: '#app',
data () {
return {
value: ''
}
},
watch: {
value() {
alert("OK");
}
}
})
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//rawgit.com/mengxiong10/vue2-datepicker/master/dist/build.js"></script>
<div id="app">
<date-picker v-model="value" lang="en" type="datetime" format="yyyy-MM-dd hh:mm:ss a" :time-picker-options="{
start: '00:00',
step: '00:30',
end: '23:30'
}"></date-picker>
{{ value }}
</div>
I have seen the package you are using for date time picker and I doubt they support #change event. Are you sure they do?
As a work around however, You can use computed properties or watchers to watch for changes in the value variable. Here is the updated fiddle https://jsfiddle.net/aw5g3q9x/2/

Categories