Vue.js get all v-model bindings - javascript

With Vue.js you can you bind form input to a property:
https://v2.vuejs.org/v2/guide/forms.html
I am working on a project where I 'dynamically' generate a form though. Here the v-model bindings are just attributes that are being set based on the name that an input has.
The problem though is that I am left wondering how to properly get these v-model bindings. So far all I have see is people manually setting a property on their Vue instance for the binding:
new Vue({
el: '...',
data: {
checkedNames: []
}
})
Is it possible to somehow grab all of the v-model bindings though without setting up the data properties manually?
When creating a dynamic form with a variation an dynamic number of fields this would help out a lot.
I guess one option is simply retrieving the name atributes from the input with javascript but I am hoping there might be something in place already since v-model is probably calling a setter that might already be known in the Vue instance.
Reworked the example from the answer:
https://jsfiddle.net/yMv7y/2477/

According to the official documentation:
it’s possible to add reactive properties to a nested object using the Vue.set(object, key, value) method.
This means that your starting data can be something like:
{
customForm: [],
values: {}
}
Let's assume customForm is an array of field objects that describe a bunch of fields in your custom form. It's empty at the beginning because you say your form will be created dynamically.
Once you generate that dynamic data, all you need to do is assign it to customForm and loop through it to add reactive properties with the aforementioned Vue.set method.
Here's a JSFiddle with an example. I'm using this.$set, but that's just an alias for Vue.set.

Related

How v-model make a property of object reactive?

Link to my project:
https://codesandbox.io/s/v-model-3j96f
As of my link above, the is a file named HelloWorld.vue inside the "components" folder:
inputvalue.bbbb is a reactive data which is defined in data option, but
It's weird that inputvalue.cccc will become reactive after input with the v-model, but inputvalue.cccc will not reactive with #input.
In this question (Vue.js bind object properties), the first situation should not be possible.
Using v-model will automatically use $set to set the values on nested properties. This ensures this it works with array indices, as well as working for object properties that don't exist, as per your example.
If you're unfamiliar with $set it is documented here:
https://v2.vuejs.org/v2/api/#vm-set
The code for this part of v-model in Vue is here:
https://github.com/vuejs/vue/blob/399b53661b167e678e1c740ce788ff6699096734/src/compiler/directives/model.js#L44
In your example there are two inputs that use cccc. As you noticed, if you edit the input that uses v-model then everything works fine. However, if you use the :value/#input input first then it doesn't work, even if you subsequently use the v-model input. The behaviour is, somewhat oddly, determined by which of those two inputs you edit first.
The reason for that can be seen in the code for $set:
https://github.com/vuejs/vue/blob/399b53661b167e678e1c740ce788ff6699096734/src/core/observer/index.js#L212
The problem is that $set will only add a reactive property if the property doesn't already exist. So if you use the :value/#input input first it will create a non-reactive cccc property and once that is created it can't be made reactive, even if you use $set. It would have to be removed using delete before it could be re-added reactively.

Vue JS custom component v-model

Hello everyone i have a bit of a problem trying to get v-model to work on a custom component i've created. The problem is that this component consists of two inputs, and each time these are changed i emit the "input" event and bind it to an array i have on the parent.
<key-value-input v-for="n in inputs" v-model="provider.params"></key-value-input>
Then in the Component itself...
updateData() {
this.$emit('input', {
key: this.inputData.key,
value: this.inputData.value
})
}
This kinda works the problem is that it replaces provider.params from the original empty array into an object containing only one of the several key-value combinations i might have since this component can be duplicated at runtime...
So the question is, how do i make it so that v-model can fetch the data from each sub-component and simply set it as objects in an array on the parent?
If I understand you correctly, you can simply use v-model on the array element itself:
<key-value-input v-for="n in inputs" v-model="provider.params[n-1]"></key-value-input>
Here's the JSFiddle: https://jsfiddle.net/2be4maxm/

The template cannot be rendered by Object in vue.js

In this demo, (https://jsfiddle.net/ccforward/fa35a2cc/) I cannot render the template and the data resultWrong equals {}
In this demo, (https://jsfiddle.net/ccforward/zoo6xzck/), if I use a temporary variable to save the async data ,then I can get the result and render the template
If I add another function named as getRightData() in the methods, then the getWrongData() can work and the template can be rendered.
link: https://jsfiddle.net/ccforward/7f42owpc/4/
If I delete the getRightData() method, then the getWrongData() cannot work.
link: https://jsfiddle.net/ccforward/7f42owpc/3/
Vue cannot detect properties that are added dynamically to an object unless you add them using set.
Here is your first fiddle updated to properly add properties to an empty object using this.$set.
For your demos, the first does not work because you add the properties using an index and Vue doesn't know that it needs to update the DOM.
The second demo works because the base value, resultRight, is set to a completely different value. resultRight is a reactive value and when it changes to a different value, Vue is aware that it needs to update the DOM.
The third demo appears to work, but it only works because resultRight changes, and because it is reactive, Vue knows to update the DOM. resultWrong is rendered at the same time but only because Vue rendered it based on the change in resultRight.
The fourth demo fails for the same reason the first demo failed. resultWrong gets new properties, but Vue doesn't know about those properties. And because you are not changing the object reference (as when you change resultRight to tmp), Vue doesn't have any idea it needs to update the DOM.

Items added to list are non-reactive in version 2 of Vue.js

In Vue 1.0 I used to add items to an array used in a v-for by simply calling items.push({}) as you can see here:
http://jsbin.com/figiluteni/1/edit?html,js,output
The exact same code in Vue 2.0 inserts a non-reactive object to the array:
http://jsbin.com/zuwihahiwa/1/edit?html,js,output
(Note that the newly added items are not live updated when edited)
<button #click="items.push({})">Add item</button>
I know that Vue inserts hooks on arrays when initialized, but being a Vue model binding that creates the new item's "name" property, I thought it could be automatically hooked like in Vue 1.
I find this new behavior very inconvenient, for it forces me to add a prototype of the object I want to add in Vue's data and clone it:
http://jsbin.com/bamasobuti/1/edit?html,js,output
In Vue's data:
item_prototype: {id: null, name: ""}
In the template:
<button #click="items.push(_.clone(item_prototype))">Add item</button>
My question is: Is there a recommended way of adding elements without having to keep a prototype of an empty element?
The change is not related to reactivity system change, but rather how v-model works in 2.0: it no longer magically creates non-existent paths and make them reactive for you.
This change is intended to force you to think about your data shape and to make your application state more predictable, similar to how you are expected to declare the reactive properties in your component's data option.
If I were you, I'd create a method and just do this.items.push({ id: null, name: '' }). There's no need to clone it.
According Vue's documentation, v-model="item.prop" is just syntactic sugar for:
v-bind:value="item.prop" v-on:input="item.prop = $event.target.value".
To make it work, just stop using
v-model="item.prop" and use this instead:
:value="item.prop" #input="$set(item,'prop',$event.target.value)"

Best practices for the input helper in new Ember components

I'm currently learning about Ember's new data-down, actions-up paradigm for components. As discussed here, however, sometimes I want to allow the child component to modify the property explicitly. This is where the mut helper comes in: it creates a wrapper for the passed in value, containing a (readonly?) value and a function to update it. The example on that page is for a simple button which increments a counter.
How does this concept work if I'm using the input helper inside a component? For example, let's say I'm building a form which consists of a bunch of special form components:
// templates/index.hbs
<form>
{{form-control value=(mut model.firstValue)}}
{{form-control value=(mut model.secondValue)}}
</form>
If the form-control component just has the task of wrapping the input control, how do we use the passed-in mut object correctly? Is it something like?
// templates/components/form-control.hbs
{{input type="text" value=attrs.value.value input=attrs.value.update}}
My thinking here: the value of the input element is set to the value of the mut object, and whenever the input value changes (HTML5 input event) the update method of the mut object is called to set the model property to the new value. It seems there's something wrong with my thinking though, because this doesn't work. What is the "standard" way of doing this now? I'm using Ember 1.13.8.
In classic components (as opposed to glimmer components), all bindings are mutable, so it is not generally necessary to use the mut helper. The following should work fine:
// templates/index.hbs
<form>
{{form-control value=model.firstValue}}
{{form-control value=model.secondValue}}
</form>
// templates/components/form-control.hbs
{{input type="text" value=value}}
The intended use of both the mut helper and of attrs is for glimmer components, also called angle bracket components, which are currently not released in Ember.js' stable releases.

Categories

Resources