Reputation: 23
i have a number field, that i want to bind value from an array like this :
<div v-for="p in products">
<input type="number" :value="carModel[p.name]" />
</div>
where p.name is a string (product name), car_a :
const app = Vue.createApp({
data() {
return {
products: {...},
carModel:[{car_a:4}, {car_b:2} ]
}
}
...
But this does not works, the input remains empty, while following runs without issue :
<div v-for="p in products">
<input type="number" :value="carModel" />
</div>
const app = Vue.createApp({
data() {
return {
products: {...},
carModel:4
}
}
...
So, my question is, how to bind the value properly from array if i have the key ?
thank you
Upvotes: 2
Views: 5142
Reputation: 285430
First off, I wonder if your carModel array item object structure could be improved; perhaps better would be something like:
products: ["car_a", "car_b"],
carModel: [
{
name: "car_a",
value: 4,
},
{
name: "car_b",
value: 2,
},
{
name: "car_c",
value: 3,
},
]
I assume that the Strings held in the products array are a sub-set of the Strings in the carModel array of objects, and since you want an input that is reactive with the data, you will want the input's model to be the values held by each carModel object. So rather than v-for loop over the products array, v-for loop over the carModel but filter out the elements whose Strings are not held by the products array. Since we should not combine v-for with v-if, this filtering should be done in a computed property:
computed: {
filteredCarModel() {
return this.carModel.filter(cm => {
return this.products.includes(cm.name);
});
}
},
so then in the HTML template you can loop over the computed property:
<div v-for="cm in filteredCarModel" :key="cm.name">
<label :for="cm.name">{{ cm.name }} </label>
<input type="number" :id="cm.name" v-model="cm.value" />
</div>
This will display proper values in the input elements, and these elements will remain reactive to the model such that changes to the inputs will cause changes to the data model, and visa-versa. Thus the display will be truly bound to the data model, which is what you're asking and what Vue.js is all about.
Here is a sample HTML showing that the data is in fact reactive:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta charset=utf-8" />
<title>Vue Example</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<h1>Vue Example</h1>
<div id="app">
<h2>Show Data</h2>
<div v-for="cm in carModel" :key="cm.name">
{{ cm.name }} : {{ cm.value }}
</div>
<h2>Change Data</h2>
<div v-for="cm in filteredCarModel" :key="cm.name">
<label :for="cm.name">{{ cm.name }} </label>
<input type="number" :id="cm.name" v-model="cm.value" />
</div>
</div>
<script>
Vue.createApp({
data() {
return {
products: ["car_a", "car_b"],
carModel: [
{
name: "car_a",
value: 4,
},
{
name: "car_b",
value: 2,
},
{
name: "car_c",
value: 3,
},
],
};
},
computed: {
filteredCarModel() {
return this.carModel.filter((cm) => {
return this.products.includes(cm.name);
});
},
},
}).mount("#app");
</script>
</body>
</html>
</html>
Note that if the products array is not a subset of the carModel array, if all the Strings present in products are also present in carModel name fields, then there will be no need to have a filteredCarModel()
computed property.
Upvotes: 2
Reputation: 27232
Observations :
products
should be an array to iterate via v-for
.carModel
is an array. You can not access object properties directly. Access it via index
.Working Demo :
new Vue({
el: "#app",
data: {
products: [{name: 'car_a'}, {name: 'car_b'}],
carModel:[{car_a: 4}, {car_b: 2}]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(product, index) in products" :key="index">
<input type="number" :value="carModel[index][product.name]"/>
</div>
</div>
Upvotes: 0
Reputation: 146
change your carModel to hash
carModel: { 'car_a': 4, 'car_b': 2 }
because what you are trying to do is access array by string(which it should be number as index of the array)
Upvotes: 0