Vue can't set inputs after receiving response from request - vue.js

I'm new to Vue.js and I have problem with binding on vue-bootstrap modal. I have a form inside vue-bootstrap-modal, and there is a field with NIP number, and onChange watcher bound to this field. And this watcher sends a request and I would like to set response of that request to other inputs, something like this:
HTML:
<div id="app">
<h2>Todos:</h2>
<form>
<input
name="model1"
v-model="model1">
<input
name="model1"
v-model="model2">
</form>
</div>
JS:
new Vue({
el: "#app",
data: {
model1: '',
model2: ''
},
watch: {
model1: function(todo){
Vue.http.get('https://jsonplaceholder.typicode.com/posts/1').then((response) => {
console.log('response', 'response')
this.model2 = 'test'
})
}
}
})
https://jsfiddle.net/8cdsnL91/95/
Here it is working perfectly, but on inside my bootstrap modal the values are setting after I make change to this input. So I write 10digit number, method is sending a request, I receive response, and trying to set response to the models, and when I try to console.log model the values are there, but the view updates after I interact with form. In AngularJS, I would need to use something like $scope.$apply(). Any help?

Related

Vue v-on:click change it to load or mouse over event

I am trying to get v-bind:value on to function reservationBy() as load event instead of v_on:clickevent. Right now it passes the value when I click on it only.
Is there a way to make it load automatically or use mouse over event? I even try to use v-on:load and v-on:focus event but it did not work.
View
<div id="app">
<input v-bind:value="2" v-on:click="reservationBy"/>
</div>
Script
new Vue({
el: "#app",
data: {
},
methods: {
reservationBy: function(e) {
var peopleBookedId = e.target.value;
console.log(peopleBookedId);
}
}
})
Here is example on JSFIDDLE
https://jsfiddle.net/ujjumaki/yz0p1vqL/4/
#mouseover and #mouseleave will do the job.
<input v-bind:value="2" #mouseover="reservationBy"/>
or
<input v-bind:value="2" #mouseleave="reservationBy"/>
If using v-model is not an option (that would be the easiest way), and you want to execute the function when component is rendered, you can use ref and access value in mounted hook:
<input ref="myInputRef" :value="2" />
Script:
mounted: function() {
console.log(this.$refs.myInputRef.value);
}

input box automatically changed to original value

When I change the input box, it will automatically change to original value by itself. It seems the reason is btnDisabled has been changed, because if I remove the line of this.btnDisabled = !this.btnDisabled; the input box will no more be automatically changed. I want to know why btnDisabled will affect the input box's value?
const vm = new Vue({
el: '#app',
data: {
btnDisabled: false,
total: 25,
},
created() {
setInterval(() => {
this.btnDisabled = !this.btnDisabled;
}, 500);
},
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<input type="text" v-bind:value="total">
<button v-bind:disabled="btnDisabled">test</button>
</div>
This is because Vue is rerendering the "component" and the value is still technically 25. You can use v-model or #input to update the data or you can use v-once to prevent Vue from rerendering the input text box.
const vm = new Vue({
el: '#app',
data: {
btnDisabled: false,
total: 25,
},
created() {
setInterval(() => {
this.btnDisabled = !this.btnDisabled;
}, 500);
},
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<input type="text" v-bind:value="total" v-once>
<button v-bind:disabled="btnDisabled">test</button>
</div>
There is an answer by Steven B which might solve your problem but I would like to add a little bit about the problem identifying the cause. The problem is in the one-way-binding, what I mean is that, when you are using the following:
<input type="text" v-bind:value="total">
You are introducing a new separate state in DOM by allowing the user typing in the input. So, when the user types into the input, the data.total property is not being updating, it's still 25 but the DOM input has new value. In that case, when setInterval fires and data.btnDisabled is updated, the Application's state is changed and then VUE just force the component to be re-render to keep the data and the DOM in sync. I would prefer v-model instead of :value.

Show value in template in VueJS

I have some code below, I want show "header" in template and show or hide when header not null.
<div id="hung">
<cmx-test v-bind:header="${properties.header}"></cmx-test>
</div>
<script>
Vue.component('cmx-test', {
props: ['header'],
template: '<h1 class=\"fillColor\" data={{this.header}}></h1>'
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#hung'
});
</script>
There is some syntax mistake in your code, to insert text into tag you can achieve with v-text attribute not data={{this.header}}.
And if you wanna hide some tag or component based on data value, you can use v-if.
And the last thing is if you wanna pass value intro component you can achieve that with this way v-bind:header="value", and value is variable which hold value you wanna pass.
<div id="hung">
<cmx-test v-if="header" v-bind:header="value"></cmx-test>
<button #click="header = true">Display</button>
</div>
<script>
Vue.component('cmx-test', {
props: ['header'],
template: '<h1 class=\"fillColor\" v-text="header"></h1>'
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#hung',
data: {
header: null,
value: "Hello World!"
}
});
</script>
Your question is not totally clear. You have the component receiving the prop header but header is not defined on the main Vue instance. You need to be passing that prop from the main data object / Vue instance into the component to use it there.
<div id="hung">
<cmx-test v-if="header" :header="header"></cmx-test>
</div>
<script>
Vue.component('cmx-test', {
props: ['header'],
template: '<h1 class=\"fillColor\" :data="header">{{header}}</h1>'
});
// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
el: '#hung'
data:{
header: null,
}
});
</script>
Also using the same data object header to control whether the component is rendered or not using v-if. So if header is null or false it wont be rendered. When it becomes true or contains a value it will be rendered and the value of header will be passed to component through binding it (e.g. :header="header")

Is it possible to globally bind to a change event?

I would like to trigger a method everytime the user switches to another field in a form. This does the job:
new Vue({
el: "#root",
data: {
theContent1: "",
theContent2: ""
},
methods: {
changeFun() {
console.log('change')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.6/vue.js"></script>
<div id="root">
<form>
<input v-model="theContent1" #change="changeFun()">
<input v-model="theContent2" #change="changeFun()">
</form>
</div>
It is however repetitive when there are many fields. Is there a way to globally bind to a method for any change?
Note: I do not want to set a watch on the content of data - I need the method to be trigerred when the edited element changes, not when its content does. A practical example would be a submit once a field is completed and the user leaves it (but wihout submitting at each change of the value of the field while it is edited).
Just put your event listener at the root of your div. All Dom events traverse the Dom down from the root, to the element that generated the event, then back up again ! You can listen for them at any level. Use event.target and event.currentTarget to find out what generated the event and what captured it.
Note that, for this reason, it's super agressive to stop the propagation of an event. All kinds of things above your element might have an interest in the events it generates.
new Vue({
el: "#root",
data: {
theContent1: "",
theContent2: ""
},
methods: {
changeFun(event) {
console.log('change from '+event.target.id)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.6/vue.js"></script>
<div id="root" #change="changeFun">
<form>
<input id="one" v-model="theContent1">
<input id="two" v-model="theContent2">
</form>
</div>
You could use watchers:
new Vue({
el: "#root",
data: {
theContent1: "",
theContent2: ""
},
watch: {
theContent1(newVal) {
console.log('change from theContent1: ', newVal)
},
...
}
})
With this you'll have to set watchers for each too...

Load default value from HTML input to vue.js data

I wonder if it is possible to load value of tag value as default value for vue.js data?
Works fine with
coupon: $('#coupon').val(),
but I really do not want to use jQuery.
Code is available here: https://jsfiddle.net/4a80dnfo/1/
So I found a way to get this done using the beforeMount() hook.
Assuming this HTML:
<div id="coupon-code">
<input ref="coupon" v-model="coupon" value="99PI_ORG" />
</div>
This Javascript should get the job done:
new Vue({
el: '#coupon-code',
data: {
coupon: ''
},
beforeMount: function() {
this.coupon = this.$el.querySelector('[ref="coupon"]').value;
}
// methods and such here.
}
});
I ended up using the beforeMount() hook after some trial an error. Some things I've learned which may be relevant:
this.$refs does not exist in the created() hook.
this.$refs.coupon.value returns an empty string in the mounted() hook.
The ref attribute of an element is deleted before the mounted() hook, so something like this.$el.querySelector('input[ref=coupon]') does not work.
You can use this.$el.querySelector('input[data-ref=coupon]').attributes['value'].value inside mounted(), but this seems worse to me than using beforeMount().
If anyone has suggestions on how to do this better, I'm very open to feedback. This solution still feels sub-optimal to me.
In your jsfiddle you are using v-model, so in your data() you just have to set your desired value
Edit: updated code to use v-bind
new Vue({
el: '#app',
data: {
coupon: 'You value here',
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.0/vue.js"></script>
<div id="app">
<input id="coupon" type="text" name="coupon" :value="coupon" />
</div>
<input name="coupon" v-model="coupon" value="def val">
window.app = new Vue({
el: '#xxx',
data: {
coupon: document.querySelector("input[name=coupon]").value
}
...
});