Vue JS call function on v-model data() change - javascript

I want to call a function on data change through v-model
HTML Part:
<input
type="date"
name="date"
id="date"
v-model="inputDate"
#change="recallMeetingDetails"
/>
VueJS Part:
data(){
return(){
inputDate: new Date().toISOString().slice(0, 10),
}
}
methods: {
recallMeetingDetails(){
console.log(this.inputData);
}
}
Now this code works fine, but in the console, I am getting the following error:
[Vue warn]: You may have an infinite update loop in a component render function.
How can I do the functionality through any other method?

You can try like following snippet :
new Vue({
el: '#demo',
data(){
return {
inputDate: new Date().toISOString().slice(0, 10)
}
},
methods: {
recallMeetingDetails(date){
this.inputDate = new Date(date).toISOString().slice(0, 10)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<input
type="date"
name="date"
id="date"
:value='inputDate'
#input="recallMeetingDetails($event.target.value)"
/>
<h3>{{ inputDate }}</h3>
</div>

Using v-model is a great idea!
Use a watcher to watch the reactive data instead of #change on the input element, and call a function when the reactive variable changes: like this
<template>
<input
type="date"
name="date"
id="date"
v-model="inputDate"
/>
</template>
<script>
export default {
data() {
return {
inputDate: new Date().toISOString().slice(0, 10)
}
},
watch: {
inputDate(value) {
console.log(value)
}
}
}
</script>

v-model watches for the value and updates it in data, try to use v-bind:value="inputDate" instead of v-model

So I managed to find a solution, the issue was in a different function.
In data(), I had 2 variables, which I was altering in a different function.
data(){
return{
inputDate: new Date().toISOString().slice(0, 10),
topValue: 0,
heightValue: 78,
}
}
fnWithIssue(x,y){
this.topValue = x + this.topValue;
this.heightValue = y + this.heightValue;
return{
top: `${topValue}px`,
height: `${heightValue}px`,
}
}
Then in a template, I was passing the aforementioned return as Inline styling, the template was in turn inside a v-for, which caused the infinite loop
Instead I was able to fix the issue by removing the data's topValue and heightValue and just decalred them in the fnWithIssue(x,y)
fnWithIssue(x,y){
let topValue = x + topValue;
let heightValue = y + heightValue;
return{
top: `${topValue}px`,
height: `${heightValue}px`
}
}

Related

How to display data from vue javascript to html

I have written few lines of code using javascript in Vue framework. I can not display date on html from var. I used vue-bootstrap for styles. Any suggestion is app?
<template>
<div class="app">
<b-form-datepicker id="datepicker" class="weekpicker" placeholder="Select a week" local="en"></b-form-datepicker>
<div class="w-75 p-3 mb-1 text-light">
<b-form-select class="weekpicker" onfocus="myFunction()">
<b-form-select-option hidden value="">Select a week</b-form-select-option>
<b-form-select-option id="mydate" value="">{{ myFunction() }}</b-form-select-option>
<b-form-select-option type="date" value=""></b-form-select-option>
<b-form-select-option type="date" value=""></b-form-select-option>
</b-form-select>
</div>
<button><span>Submit</span></button>
</div>
</template>
<script>
export default {
name: 'TS_home',
data() {
return {
};
},
methods: {
myFunction() {
let x = new Date();
let current_date = x.toDateString();
x.setDate(x.getDate() + 7);
let seventh_date = x.toDateString()
document.getElementById("mydate").innerHTML = current_date + " - " + seventh_date;
}
}
};
</script>
As #Phil said since you are using Vue you should define the data property for the date like so:
data() {
return {
myDate: null
}
}
When it comes to date pickers it is usually #change event or v-model.
Try:
<b-form-datepicker id="datepicker" class="weekpicker" placeholder="Select a week" local="en" #change="myDate=$event"></b-form-datepicker>
Then display the property in your HTML template like:
{{myDate}}
Another possibility is to use vue-bootstrap if that is not what you have installed already. You would do it like this:
npm install vue-bootstrap-datetimepicker --save
then in your component
// Import required dependencies
import 'bootstrap/dist/css/bootstrap.css';
// Import this component
import datePicker from 'vue-bootstrap-datetimepicker';
then in your data
data() {
return {
myDate: new Date(),
options: {
format: 'DD/MM/YYYY',
useCurrent: false,
}
}
}
and in your HTML template
<date-picker v-model="myDate" :config="options"></date-picker>
and to display that date you would again use:
{{myDate}}
Please refer to the documentation for more detailed information.
I hope it helps. Good luck.
You should use the data property instead of manipulating the dom
data() {
return {
myDate: ''
}
}
Inside the function
myFunction() {
let x = new Date();
let current_date = x.toDateString();
x.setDate(x.getDate() + 7);
let seventh_date = x.toDateString()
this.myDate = current_date + " - " + seventh_date;
}
In the html, use the vue-event handler
<b-form-select class="weekpicker" #focus="myFunction()">
<b-form-select-option id="mydate" value="">{{ myDate }}</b-form-select-option>
Hope this will help :)

Vue.js v-for not rendering component

I have the following issue, for some reason, the v-for will not render at all. Please find the fiddle here https://jsfiddle.net/tadeyemi/k6s4gv85/ I have absolutely no idea why it isn't working. Someone care to shed some light?
<div id="app">
<h1>Finds</h1>
<div>
<input ref="option">
</div>
<button v-if #click="addFind">
New Find
</button>
<p v-for="(option,idx) in options.slice(1)">
<span #click="removeOption(idx+1)">Option{{idx+1}}: {{option}}</span>
</p>
</div>
and the JavaScript as follows:
new Vue({
el: '#app',
data: {
options: [],
count:0
},
methods: {
addFind: function () {
var msg = this.$refs.option.value;
console.log(this.options);
if( msg.trim() != "" ){
this.count++;
var i = this.count;
this.options[i]= this.$refs.option.value.trim();
}
},
removeOption:function(index){
this.options.splice(index,1);
this.count--;
}
}
});
There are some issues with your code, but the most prominent is that you break some reactivity rules explained here: https://v2.vuejs.org/v2/guide/reactivity.html#For-Arrays
Vue cannot detect the following changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue When you modify the length of the
array, e.g. vm.items.length = newLength
Basically: this.options.push(msg.trim()); would work, while this.options[i]= this.$refs.option.value.trim(); won't
I edited the fiddle a little to make it work: https://jsfiddle.net/63jyw7gz/

How do I pass input text using v-on:change to my vue method?

How can I pass the input value from my html to my vue method called checkEx
ist() ? I would like to retrieve that value within my checkExist() method. Could any advice how I can do this? I am still new to vue.
HTML:
<input type="text" class="form-control" placeholder="Email*" v-model="form.email" v-validate="'required|email'" v-on:change="checkExist">
VUE ELEMENT:
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
methods: {
checkExist:function(){
}
}
})
First you need to define form:{email:"", ...} in the data as well.
Pass $event inside checkExist() .
Something like this,
function callMe() {
var vm = new Vue({
el: '#root',
data: {
form:{email:""},
email:""
},
methods: {
checkExist(event){
this.email=event.target.value;
}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<input type="text" #input="checkExist($event)" class="form-control" placeholder="Email*" v-model="form.email">
<p>email: {{email}}</p>
</div>
The v-model should already bind that input event.
But you can pass the event to v-on:change like this:
v-on:change="event => checkExist(event)"
Check exist would need to accept the event as a parameter.
The value of the input will now be accessible inside the vue function via event.target.value.
checkExist: function(event){
let value = event.target.value
}
Simpler even more, you don't need to pass the entire event to your handler function.
#change="checkExist($event.target.value)"
.
checkExist: function(value){
}
We could do it in ES6 syntax without using 'v-model' as below
<input v-on:change="(event) => inputValue = event.target.value" :value="inputValue" type="text"/>

Vue.js keyup events and v-model length on Android not working as expected

On Android the length of v-model is returning 0 on keyup unless its a number or the space bar key. Does anyone know why that is and how to make it fire the keyup event no matter what key it is and get the length? Here is a cleaned up version of what I have:
<template>
<div class="typeahead">
<input
v-model="query"
v-on:keyup="suggestTerms"
>
</div>
</template>
<script>
export default {
data () {
return {
query: '',
}
},
methods: {
suggestTerms () {
console.log('query length = ' + this.query.length);
}
}
}
</script>
P.S. This works on every browser and device except Android.
There have been instances when v-model didn't update on mobile in some cases. Issue on Forum (current), Another from Forum
You can also code the v-model explicitly, it works in both android and pc.
function callMe(){
var vm = new Vue({
el : '#root',
data : {query : ''},
methods: {
suggestTerms () {
console.log('query length = ' + this.query.length);
}
}
})
}
callMe();
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<h3>Decomposed</h3>
<div>
<input type='text' :value='query' #input='evt=>query=evt.target.value' v-on:keyup="suggestTerms">
<b>{{query}}({{query.length}})</b>
</div>
</div>

Avoid mutating a prop directly in VueJS 2

First of all, I am just starting playing with VueJS, so this cannot be a VueJS version thing as suggested here
It might be a duplicate of :
How to solve [Vue warn]: Avoid mutating a prop directly since the value will be overwritten on vue.js 2? - the difference is that I am only trying to set the values with v-bind, once.
Avoid mutating a prop directly since the value will be overwritten - This also looks somehow similar, but the solution didn't worked for me.
What's the correct to modify VUE component via javascript? - this solution looks pretty much what I have in my case
vuejs update parent data from child component
My problem starts with my Html looking like this:
<div id="app">
<div class="row">
<div class="form-group col-md-8 col-md-offset-2">
<birthday-controls
:birthDay="birthDay"
:birthMonth="birthMonth"
:birthYear="birthYear">
</birthday-controls>
</div>
</div>
</div>
and JS:
Vue.component('birthday-controls', {
template: `<div class="birthday">
<input type="text" name="year" placeholder="yyyy" v-model="birthYear" size="4" maxlength="4"/>
<input type="text" name="month" placeholder="mm" v-show="validYear" v-model="birthMonth" size="3" maxlength="2"/>
<input type="text" v-show="validYear && validMonth" name="day" placeholder="dd" v-model="birthDay" size="2" maxlength="2"/>
</div>`,
props: ['birthDay', 'birthMonth', 'birthYear'],
computed: {
validYear: function() {
return (this.birthYear > new Date().getFullYear()-100 && this.birthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.birthMonth > 0 && this.birthMonth <= 12)
},
validDay: function() {
return (this.birthDay > 0 && this.birthDay <=31) //I have to add more checking here for february, leap years and ....
}
}
});
new Vue({
el: '#app',
data: function() {
return {
birthDay: "",
birthMonth: "",
birthYear: ""
}
},
});
I have prepared codepen here: http://codepen.io/AngelinCalu/pen/OpXBay
However, the second answer from here: vuejs update parent data from child component makes me realise that I'm missing something
In that example it sets an this.$emit('increment') inside one of the methods, and triggers that on specific event.
In this other example: Update a child's data component to the father component in vue.js using .vue webpack(vue2) , the answer suggest adding a watch to emit the change.
watch: {
val() {
this.$emit('title-updated', this.val);
}
}
Now I'm even more confused! What is the right (or best) way to deal with this problem?
Note:
If I remove from the initial html :
:birthDay="birthDay"
:birthMonth="birthMonth"
:birthYear="birthYear"
It still works as expected, but I'm still getting that Vue warn, however, if I'm following the method from here: https://stackoverflow.com/a/41901150/2012740, it stops working, but I'm getting no error.
My Updated code: https://jsfiddle.net/angelin8r/647m7vdf/
To conclude: I need the functionality from the beginning but without the [Vue warn]
This is what I got in my initial example:
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "birthYear"
The warning is the result of setting v-model to the value of your properties. The reason is because if you change birthYear, birthMonth, or birthDay outside the component, then whatever the value is currently inside the component will be immediately overwritten.
Instead, capture a copy.
Vue.component('birthday-controls', {
template: `<div class="birthday">
<input type="text" name="year" placeholder="yyyy" v-model="internalBirthYear" size="4" maxlength="4"/>
<input type="text" name="month" placeholder="mm" v-show="validYear" v-model="internalBirthMonth" size="3" maxlength="2"/>
<input type="text" v-show="validYear && validMonth" name="day" placeholder="dd" v-model="internalBirthDay" size="2" maxlength="2"/>
</div>`,
props: ['birthDay', 'birthMonth', 'birthYear'],
data(){
return {
internalBirthDay: this.birthDay,
internalBirthMonth: this.birthMonth,
internalBirthYear: this.birthYear
}
},
computed: {
validYear: function() {
return (this.internalBirthYear > new Date().getFullYear()-100 && this.internalBirthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.internalBirthMonth > 0 && this.internalBirthMonth <= 12)
},
validDay: function() {
return (this.internalBirthDay > 0 && this.internalBirthDay <=31) //I have to add more checking here for february, leap years and ....
}
}
});
You did this almost exactly in your fiddle, but you did not correct your computed values.
computed: {
validYear: function() {
return (this.birthYear > new Date().getFullYear()-100 && this.birthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.birthMonth > 0 && this.birthMonth <= 12)
},
validDay: function() {
return (this.birthDay > 0 && this.birthDay <=31) //I have to add more checking here for february, leap years and stuff
}
},
should be
computed: {
validYear: function() {
return (this.var_birthYear > new Date().getFullYear()-100 && this.var_birthYear < new Date().getFullYear()-14)
},
validMonth: function() {
return (this.var_birthMonth > 0 && this.var_birthMonth <= 12)
},
validDay: function() {
return (this.var_birthDay > 0 && this.var_birthDay <=31) //I have to add more checking here for february, leap years and stuff
}
},

Categories

Resources