Detecting changes to an input value - vue2 - javascript

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/

Related

Angular state not updating until click anywhere

Very new to Angular, and just trying to get a feel for it. I have an input component:
import { Component } from '#angular/core';
#Component({
selector: 'app-input',
templateUrl: './input.component.html',
})
export class InputComponent {
q = '';
queryChange(value: string) {
this.q = value;
}
}
It's html:
<div>
<input #query type="text" (change)="queryChange(query.value)" />
<button>Search</button>
<div>{{ q }}</div>
</div>
When I type into the input, the {{ q }} doesn't update until I click anywhere on the screen, or hit enter. Almost like refocusing. Coming from React I'm confused as to why this happens with the Angular's (change) rather than updating as I type.
My first thought was that maybe because I'm passing the value of the input to queryChange(query.value) instead of passing the event value like I would usually do in React.
I think the problem is about the DOM and not Angular. You should use (input) instead of (change) if you want the event to trigger every time you type.
<input #query type="text" (input)="queryChange(query.value)" />
See this StackBlitz, as well as change and input MDN references. Specifically, MDN says about change:
Unlike the input event, the change event is not necessarily fired for each alteration to an element's value.

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

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="..." />

Vue JS How to bind the onChange event to change the value in input

I am using npm package vue-range-component with which I change the value with a slider and then that value is reactively changed in the input
My problem is that I can’t apply the onChange event for inputs, I need to be able to change the value in the input, for example, put the number 70, and then this number was applied to the vue-range-component, something like that
Here is my sandbox code
<template>
<div class="app-content">
<div>
<input type="text" v-model="value[0]" />
<input type="text" v-model="value[1]" />
</div>
<vue-range-slider
v-model="value"
:min="min"
:max="max"
:formatter="formatter"
style="margin-top: 40px"
></vue-range-slider>
<div class="multi-range-value-container">
<p>{{ value[0] }}</p>
<p>{{ value[1] }}</p>
</div>
</div>
</template>
<script>
import "vue-range-component/dist/vue-range-slider.css";
import VueRangeSlider from "vue-range-component";
export default {
data() {
return {
value: [0, 100],
};
},
methods: {
onChange(event) {
console.log(event.target.value);
},
},
components: {
VueRangeSlider,
},
created() {
this.min = 0;
this.max = 1000;
this.formatter = (value) => `$${value}`;
},
};
</script>
One caveat of Vue's reactivity system is that you cannot detect changes to an array when you directly set the value of an item via its index.
As explained in the link, there are two main methods of making array modifications reactive:
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
Using these methods forces the VueJS reactivity system to update its state.
To implement this solution in your example, you can use a watcher on a modelled value, an #change event or a #keyup event.
A watcher is likely the most resource intensive approach. I would suggest using #keyup (which would fire on every keypress as opposed to when you unfocus the input with #change) and then debouncing the input if the value is used to filter/sort/load anything.
If you wanted to as well, you could also directly set the entire array.
For example instead of setting value[0] = something you could do value = [...value, something];and this would be reactive.
It is indeed Vue reactivity issuse
You can fix it by not using v-model syntactic sugar but split it like this:
From:
<input type="text" v-model="value[0]" />
to:
<input type="text" :value="value[0]" #input="changeRange(0, $event.target.value)" />
define a method:
methods: {
changeRange(index, value) {
const v = parseInt(value, 10) // value from input is always string
this.$set(this.value, index, v)
}
}
Update
Above code is a fix you would need anyway but unfortunately the vue-range-component has a different issue as it blocks all user keyboard input to any input element on the same page - see this and this issue
It was already fixed by this pull request but it wasn't released yet to npm
You can use some of the workarounds described in the issues BUT given the way how the maintainer (not) handles the issue, it would be probably better for you to look around for another component with similar functionality...

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.

vuejs materializecss timepicker not get value

How can I get time value using materializecss Timepicker in Vuejs
Meterilize css Time Picker Jsfiddle LInk
It's give me value in jsfiddle but when I doing it my vuejs project it's not working..
Vue.js Code:
<v-text-field
name="start-time"
id="edit_start-time"
class="timepicker"
></v-text-field>
mounted() {
$('.timepicker').pickatime({
default: 'now', // Set default time: 'now', '1:30AM', '16:30'
fromnow: 0, // set default time to *
twelvehour: true, // Use AM/PM or 24-hour format
donetext: 'OK', // text for done-button
cleartext: 'Clear', // text for clear-button
canceltext: 'Cancel', // Text for cancel-button
autoclose: false, // automatic close timepicker
ampmclickable: true, // make AM PM clickable
aftershow: function() {} //Function for after opening timepicker
});
$('.timepicker').on('change', function() {
let receivedVal = $(this).val();
console.log(receivedVal);
});
},
NB: My fiddle works fine and if you check console it give me value but same code not work in Vue.js Project my Problem in Vuejs.. i want to get value like jsfiddle
Please use
v-model.lazy="deliverySchedule"
worked for me !!!
Jsfiddle Link With Solution own my problem
I got solution by use input
<input class="timepicker" v-model="deliverySchedule" >
I think you should not use jQuery for this.
Vue offers some nice bindings wich are working way better.
<v-time-picker v-model="myTimeValue"></v-time-picker>
In this code i bind myTimeValue (a local data variable) to the actual value of the timepicker. Now i can use it anywhere and vue deals with all updating stuff.
I think you should use ref
If you need directly access a child component in JavaScript you have to assign a reference ID to the child component using ref.
For more information take a look at Link.
How to use:
Your html should be similar to this:
<div class="input-field inline">
<label for="startDate" class="materialize-label">Start Date</label>
<input id="startDate" ref="startDate" type="date" size="12" class="startDate timepicker">
</div>
You also need to initialize it with jquery (the same way you have done it)
$('.timepicker').pickatime({
...
...
...
})
For example, when your user submits a form you just need to use: this.$refs.startDate.value
This will grab the value of the date.
If you want to bind changes from the user you can use v-model.
Otherwise, I think using v-model is unnecessary.
Vue Docs:
You can use the v-model directive to create two-way data bindings on
form input and textarea elements. It automatically picks the correct
way to update the element based on the input type
More information at: Link

Categories