Get totalsum from #onclick in vue - vue.js

I want to make the {{total}} update when I click #addToChart button and it gets the game price from the vue array.
HTML:
<p> Total Price: {{ total }} USD</p>
<button #click="addToChart" :disabled="!game.inStock"
:class="{ disabledButton: !game.inStock }">
Add to Chart
</button>
Vue:
el: "#app",
data: {
title: "",
about: "",
games: [{
id: 0,
title: "",
inStock: true,
price: 59,
},
{
id: 1,
title: "",
inStock: true,
price: 40,
},
methods: {
addToChart: function () {
this.cart += 1;
return total;
}

You need to define your total property in your data first.
Then just pass the price as argument of your addToCart function.
new Vue({
el: "#app",
data: {
title: "",
about: "",
games: [
{ id: 0, title: "Game 1", inStock: true, price: 59 },
{ id: 1, title: "Game 2", inStock: true, price: 40 }
],
total: 0
},
methods: {
addToChart: function (price) {
this.total += price
}
}
})
<script src="https://unpkg.com/vue#2.6.10/dist/vue.min.js"></script>
<div id="app">
<p> Total Price: {{ total }} USD</p>
<div v-for="game in games">
{{ game.title }}
<button #click="addToChart(game.price)" :disabled="!game.inStock">Add to Chart</button>
</div>
</div>

Related

Data is not display in correct order after update

I try to display an array of object sort by date.
When it's mount there is no problem but when i try to add new data, it is not shown in the correct order. I'm sorry but I cannot be more clear ...
Here is my code :
<template>
<div class="container">
<div class="row">
<div class="col" style="position: relative; height: 50vh">
<canvas id="graphique"></canvas>
</div>
<div>
<h1>Finds</h1>
<div v-for="(find, index) in finds" v-bind:key="index">
<input v-model="find.date" />
<input v-model="find.value" />
<input v-model="find.label" />
</div>
<input v-model="dateToAdd" />
<input v-model="valueToAdd" />
<input v-model="labelToAdd" />
<button #click="addFind">Add cost</button>
<p v-if="Chart != null">{{ Chart.data.datasets[0].data }}</p>
</div>
</div>
</div>
</template>
<script>
import Chart from "chart.js/auto";
export default {
name: "PlanetChart",
data() {
return {
Chart: null,
valueToAdd: 20,
labelToAdd: "A",
dateToAdd: "12/01/1900",
finds: [
{ date: "12/01/2020", label: "1", value: 12 },
{ date: "12/01/2021", label: "2", value: 2 },
{ date: "12/01/2000", label: "0", value: 1 },
{ date: "12/01/2023", label: "3", value: 12 },
],
};
},
mounted() {
const ctx = document.getElementById("graphique");
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "My dataset",
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: "butt",
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: "miter",
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 5,
pointHitRadius: 10,
data: this.finds,
},
],
},
options: {
parsing: {
xAxisKey: "date",
yAxisKey: "value",
},
responsive: true,
maintainAspectRatio: false,
},
});
},
methods: {
addFind: function () {
if (this.valueToAdd > 0 && this.labelToAdd != "") {
this.finds.push({
date: this.dateToAdd,
value: this.valueToAdd,
label: this.labelToAdd,
});
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart.data.datasets[0].data = this.finds;
console.log(this.Chart.data.datasets[0].data);
this.Chart.update();
this.valueToAdd = 0;
this.dateToAdd = "";
this.labelToAdd = "";
}
},
},
};
</script>
Here the result I have :
The point at the extrem right must be the first because his date is before the others points.
So it seems to be a rendering probleme and not a sort probleme.
If you need a js.fiddle let me know.
Thanks for your help !
EDIT : The only solution found is to create a function to create the graph and inside the addFind function do this :
this.Chart.destroy();
this.Chart = this.createChart(this.finds)
This is a working example with you data.
Here is the template code, I used a computed property to sort the array of data instead of sorting the actual data.
Please review the dependencies of the Chart.js package, as time series chart require external date adapters as mentioned here.
Also, there seems to be a Chart.js wrapper for Vue, perhaps you should try it.
<template>
<div class="container">
<div class="row">
<div class="col" style="position: relative; height: 50vh">
<canvas id="graphique"></canvas>
</div>
<div>
<h1>Finds</h1>
<div v-for="(find, index) in finds" v-bind:key="index">
<input v-model="find.date" />
<input v-model="find.value" />
<input v-model="find.label" />
</div>
<input v-model="dateToAdd" />
<input v-model="valueToAdd" />
<input v-model="labelToAdd" />
<button #click="addFind">Add cost</button>
<p v-if="Chart">{{ Chart.data }}</p>
</div>
</div>
</div>
</template>
<script>
import Chart from "chart.js/auto";
import "chartjs-adapter-moment";
export default {
name: "PlanetChart",
data() {
return {
Chart: null,
valueToAdd: 20,
labelToAdd: "A",
dateToAdd: "12/01/1900",
finds: [
{ date: "12/01/2020", label: "1", value: 12 },
{ date: "12/01/2021", label: "2", value: 2 },
{ date: "12/01/2000", label: "0", value: 1 },
{ date: "12/01/2023", label: "3", value: 12 },
],
};
},
mounted() {
const ctx = document.getElementById("graphique");
this.Chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "US Dates",
backgroundColor: "#fff",
borderWidth: 1,
pointBorderWidth: 1,
borderColor: "#f00",
data: this.transformedData,
fill: false,
borderColor: "red",
},
],
},
options: {
scales: {
x: {
type: "time",
time: {
unit: "month",
},
},
},
},
});
},
computed: {
transformedData() {
const d = this.finds.map((i) => {
return { x: new Date(i.date), y: i.value };
});
d.sort(function (a, b) {
return a.x - b.x;
});
return d;
},
},
methods: {
addFind: function () {
if (this.valueToAdd > 0 && this.labelToAdd !== "") {
this.finds.push({
date: this.dateToAdd,
value: this.valueToAdd,
label: this.labelToAdd,
});
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart.data.datasets[0].data = this.transformedData;
console.log(this.Chart.data.datasets[0].data);
this.Chart.update();
this.valueToAdd = 0;
this.dateToAdd = "";
this.labelToAdd = "";
}
},
},
};
</script>
So without using a computed method is it possible to do it simply by using the
import "chartjs-adapter-moment";
as Juand David mentioned. And don't forget to convert the string in Date.
Here is my solution :
<template>
<div class="container">
<div class="row">
<div class="col">
<canvas id="graphique"></canvas>
</div>
</div>
<div class="row">
<div class="col-xxs">
<h1>Mes catégories</h1>
<div v-for="(cat, index) in category" v-bind:key="index">
{{ cat.label }}
</div>
</div>
<div class="col">
<h1>Mes dépenses</h1>
<div v-for="(find, index) in finds" v-bind:key="index">
<input v-model="find.date" readonly />
<input v-model="find.value" readonly />
<input v-model="find.label" readonly />
</div>
<div>
<input v-model="dateToAdd" />
<input v-model="valueToAdd" />
<select v-model="labelToAdd">
<option
v-for="(cat, index) in category"
:value="cat.label"
v-bind:key="index"
>
{{ cat.label }}
</option>
</select>
<button #click="addFind">Add cost</button>
</div>
</div>
</div>
</div>
</template>
<script>
import Chart from "chart.js/auto";
import "chartjs-adapter-moment";
export default {
name: "PlanetChart",
data() {
return {
ctx: null,
Chart: null,
valueToAdd: null,
labelToAdd: null,
dateToAdd: null,
category: [
{ id: "salary", label: "Salaire" },
{ id: "fun", label: "Loisir" },
],
finds: [
{ date: new Date("12/01/2020"), label: "Dépense 1", value: 12 },
{ date: new Date("12/01/2021"), label: "Salariée", value: 2 },
{ date: new Date("12/01/2000"), label: "Ciné", value: 1 },
{ date: new Date("12/01/2023"), label: "Restaurant", value: 12 },
],
};
},
mounted() {
this.ctx = document.getElementById("graphique");
this.finds.sort(function (a, b) {
return a.date - b.date;
});
this.Chart = this.createChart(this.finds);
},
methods: {
createChart: function (dataToAdd) {
var toRet = new Chart(this.ctx, {
type: "line",
data: {
datasets: [
{
label: "My dataset",
fill: false,
lineTension: 0.1,
backgroundColor: "rgba(75,192,192,0.4)",
borderColor: "rgba(75,192,192,1)",
borderCapStyle: "butt",
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: "miter",
pointBorderColor: "rgba(75,192,192,1)",
pointBackgroundColor: "#fff",
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: "rgba(75,192,192,1)",
pointHoverBorderColor: "rgba(220,220,220,1)",
pointHoverBorderWidth: 2,
pointRadius: 5,
pointHitRadius: 10,
data: dataToAdd,
},
],
},
options: {
parsing: {
xAxisKey: "date",
yAxisKey: "value",
},
scales: {
x: {
type: "time",
time: {
unit: "month",
},
},
},
responsive: true,
maintainAspectRatio: false,
},
});
return toRet;
},
addCategory: function () {},
addFind: function () {
if (this.valueToAdd !== null && this.labelToAdd !== null) {
this.finds.push( { date: new Date("12/01/1990"), label: "Dépense nouvelle", value: 5 });
this.finds.sort(function (a, b) {
return new Date(a.date) - new Date(b.date);
});
this.Chart.data.datasets[0].data = this.finds;
// console.log(this.Chart.data.datasets);
this.Chart.update();
// this.Chart = this.createChart(this.finds);
this.valueToAdd = 0;
this.dateToAdd = "";
this.labelToAdd = "";
}
},
},
};
</script>

Multiple dropdowns with no duplicate value

I'm trying to replicate a Vue component, which is a list of items, each item contains a dropdown and a remove button. There will be an "Add" button that add new item to the list, which is depicted in the snippet below.
The requirement is that when ever user select an option, that option will not be available (or remove) for any other item. In other words, selected option values should not be duplicated. Which is quite similar to the idea in this question (jQuery Prevent duplicate choice in multiple dropdowns)
When user re-select or remove an item, the selected option attached to it should be added again to "available" list. The option list is therefore "reactive" and dynamic.
For example, for the first item, if I select "Option 1". "Option 1" should not be in option list when "Add new item" is clicked. And if first item is removed, "Option 1" will be available for select again, etc,. . .
This is what I got so far, the idea is that option will store all option data, selectedValueArray will responsible for storing selected option value for each item, and selectableOptions array will equal to options set minus selectedValueArray. By interacting with item (changing option, remove), selectedValueArray and selectableOptions array will be changed accordingly.
I can do this with JavaScript. However I'm new to Vue and not sure how to do it in Vue effectively. The problem of the snippet I created is that because of available options comes from selectableOptions array, so when an item is removed from selectableOptions, it will also affect selected option. (e.g: If "Option 1" is removed from this array, the dropdown in the first item will be blank because "Option 1" has already been removed from selectable list). Any help is appreciated.
var app = new Vue({
el: "#app",
data: {
options: [],
items: [],
selectableOptions: [],
selectedValueArray: [],
},
mounted() {
this.options = [
{
name: "Option 1",
value: 1,
},
{
name: "Option 2",
value: 2,
},
{
name: "Option 3",
value: 3,
},
{
name: "Option 4",
value: 4,
},
{
name: "Option 5",
value: 5,
},
{
name: "Option 6",
value: 6,
}
];
this.selectableOptions = this.options;
},
methods: {
addItem: function () {
this.items.push({
'value': 0
});
},
removeItem: function (index) {
this.$delete(this.items, index);
},
changeOption: function () {
this.selectedValueArray = [];
for (let i = 0; i < this.items.length; i++) {
let selectedValue = this.items[i].value;
this.selectedValueArray.push(selectedValue);
}
this.selectableOptions = this.options.filter(
option => {
return this.selectedValueArray.indexOf(option.value) == -1;
})
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, index) in items">
<select
v-model="item.value">
<option v-for="(option) in selectableOptions" :value="option.value">{{option.name}}</option>
</select>
<button #click="removeItem(index)">Remove this item</button>
</div>
<button #click="addItem">Add new item</button>
</div>
If you want to simply disable an option whose value is present in the items array of objects (which you are using for the v-model directive binding, so it reflects a "live" set of user-selected choices), then it is a matter of using a method to return a disabled state:
<option v-for="(option) in options" :value="option.value" v-bind:disabled="isDisabled(option)">{{option.name}}</option>
Then, you can define a isDisabled(option) method which returns a boolean to indicate if a given option's value is already present in your array:
isDisabled: function(option) {
return this.items.map(item => item.value).includes(option.value);
}
See proof-of-example below:
var app = new Vue({
el: "#app",
data: {
options: [],
items: [],
selectedValueArray: [],
},
mounted() {
this.options = [{
name: "Option 1",
value: 1,
},
{
name: "Option 2",
value: 2,
},
{
name: "Option 3",
value: 3,
},
{
name: "Option 4",
value: 4,
},
{
name: "Option 5",
value: 5,
},
{
name: "Option 6",
value: 6,
}
];
},
methods: {
addItem: function() {
this.items.push({
'value': 0
});
},
removeItem: function(index) {
this.$delete(this.items, index);
},
isDisabled: function(option) {
return this.items.map(item => item.value).includes(option.value);
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, index) in items">
<select v-model="item.value">
<option v-for="(option) in options" :value="option.value" v-bind:disabled="isDisabled(option)">{{option.name}}</option>
</select>
<button #click="removeItem(index)">Remove this item</button>
</div>
<button #click="addItem">Add new item</button>
</div>
you have to use a computed property, that filter the selectableOptions
something like this
{
computed: {
computedSelectable() {
const chosenValues = this.selectedValueArray.map((i) => i.value);
return this.selectableOptions.filter((item) =>
!chosenValues.includes(item.value)
);
},
}
}
Improved answer, <select> element with selected disabled option will not be submitted. Use v-show instead
var app = new Vue({
el: "#app",
data: {
options: [],
items: [],
selectedValueArray: [],
},
mounted() {
this.options = [{
name: "Option 1",
value: 1,
},
{
name: "Option 2",
value: 2,
},
{
name: "Option 3",
value: 3,
},
{
name: "Option 4",
value: 4,
},
{
name: "Option 5",
value: 5,
},
{
name: "Option 6",
value: 6,
}
];
},
methods: {
addItem: function() {
this.items.push({
'value': 0
});
},
removeItem: function(index) {
this.$delete(this.items, index);
},
isShown: function(option) {
return !(this.items.map(item => item.value).includes(option.value));
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(item, index) in items">
<select v-model="item.value">
<option v-for="(option) in options" :value="option.value" v-show="isShown(option)">{{option.name}}</option>
</select>
<button #click="removeItem(index)">Remove this item</button>
</div>
<button #click="addItem" v-show="items.length<options.length">Add new item</button>
</div>

how to multi filtering vue.js

just new in vue.js.
I have an array of objects which is my products, How to multi filter it?
HTML
<input type="checkbox" required v-model="selectedCategory" value="1"> // Category 1
<input type="checkbox" required v-model="selectedCategory" value="2"> // Category 2
<div>
<div v-for="product in filteredProducts">
<a href="#">
<div class="prdct-frame__img-holder">
<img :src="product.productImage">
</div>
<p>{{ product.productName }}</p>
</a>
</div>
</div>
SCRIPT
<script>
var vm = new Vue({
el: "#main",
data: {
products: [
{
productName: "Product 1",
productID: 1,
productImage: //via.placeholder.com/200x200,
categoryID: true,// 1
colorID: 1, //blue
sizeID: 1, //large
},
{
productName: "Product 2",
productID: 2,
productImage: //via.placeholder.com/200x200,
categoryID: true, // 1
colorID: 2, //red
sizeID: 2, //medium
},
{
productName: "Product 3",
productID: 3,
productImage: //via.placeholder.com/200x200,
categoryID: true, // 2
colorID: 3, //green
sizeID: 3, //small
},
{
productName: "Product 4",
productID: 4,
productImage: //via.placeholder.com/200x200,
categoryID: true, // 2
colorID: 4, //green
sizeID: 3, //small
},
],
selectedCategory: [],
},
computed: {
filteredProducts: function() {
var vm = this;
var category = vm.selectedCategory;
return vm.products.filter((product) => {
var keys = Object.keys(product);
var matchFilter = false;
category.forEach((key) => {
if(product[key] === true) {
matchFilter = true;
}
});
return matchFilter;
});
},
}
});
</script>
This Code works for filtering by category, if I filter by Category 1 it display all the products under Category 1 which is right. Now I want to filter it too by color and size.
For example if choose Category 1 and choose color is red and choose size is medium
The expected out put will be :
Product name : Product 2
Color : red
Size : medium
You should use an Array of filters:
data()
{
return {
filtration:
[
{
key: 'categoryID',
value: 2
},
{
key: 'colorID',
value: 2
},
{
key: 'sizeID',
value: 2
},
]
}
},
computed: {
filteredProducts: function() {
const arrFilters = this.filtration;
return this.products.filter((product) => {
return arrFilters.every((filter) => {
return product[filter.key] === filter.value;
});
});
},
}

Going back to previous object in array with back button in v-for

I have a component with a v-for div. each item has a click function access their respective children object. I need to have a back button that would refresh the v-for div but using the ParentId of the current item I'm in.
Scan view:
<template>
<div p-0 m-0>
<div v-show="!currentItem" class="scanBreadcrumbs">
<h2>Show location</h2>
</div>
<div v-for="item in items" :key="item.id" :item="item">
<SubScan
v-show="currentItem && currentItem.id === item.id"
:item="item"
></SubScan>
<p
class="locationBox"
#click="swapComponent(item)"
v-show="path.length === 0"
>
{{ item.title }}
</p>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
import { SubScan } from "#/components/scan";
export default {
name: "Scan",
components: {
SubScan
},
computed: {
...mapGetters(["getResourceHierarchy", "getIsDarkMode", "getFontSize"])
},
methods: {
swapComponent(item) {
this.path.push(item.title);
this.currentItem = item;
}
},
data: () => ({
currentItem: null,
path: [],
items: [
{
parentId: null,
id: 11,
title: "Location 1",
items: [
{
parentId: 11,
id: 4324,
title: "Row 1",
items: [
{
parentId: 4324,
id: 4355,
title: "Row 1.1",
items: [
{
parentId: 4355,
id: 64645,
title: "Row 1.2",
items: [
{
parentId: 64645,
id: 7576657,
title: "Row 1.3",
items: [
{
parentId: 7576657
id: 8686,
title: "Row 1.4",
items: [
{
parentId: 8686,
id: 234324,
title: "QR Code"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
})
};
</script>
SubScan component where the back button is:
<template>
<div>
<div class="scanBreadcrumbs">
<h2 v-show="path">{{ path.join(" / ") }}</h2>
</div>
<div>
<div class="showList" v-for="item in itemChildren" :key="item.id">
<p class="locationBox" #click="swapComponent(item)">
{{ item.title }}
</p>
<div class="backButton">
<v-icon #click="swapPrevious(item)" class="arrow"
>fa-arrow-left</v-icon
>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "SubScan",
props: {
item: {
type: Object,
required: true
}
},
data: () => ({
currentItem: null,
secondaryPath: [],
parentPath: []
}),
methods: {
swapComponent(item) {
console.log(item.parentId);
this.path.push(item.title);
this.parentPath.push(this.currentItem);
this.currentItem = item;
},
swapPrevious(item) {
console.log(item);
this.path.pop(this.currentItem.title);
this.currentItem = item.id;
}
},
computed: {
items(currentItem) {
return this.currentItem ? this.item.items : this.item.items;
},
itemChildren(currentItem) {
return this.currentItem ? this.currentItem.items : this.item.items;
},
path() {
return this.secondaryPath.concat(this.item.title);
}
}
};
</script>
I can only go back to the children of the object I clicked on in Scan view.
Thank you for your time.
I managed to fix my problem by assigning parent objects to each children. Then I
moved everything to Scan.vue for simplicity. This is my first project using Vue
so things might not be optimal. Scan.vue
<template>
<div p-0 m-0>
<div class="scanBreadcrumbs">
<h2 v-show="path">{{ path.join("/") }}</h2>
<h2 v-if="path.length === 0">Show location</h2>
</div>
<div>
<div v-for="item in items">
<p class="locationBox" #click="swapComponent(item)">
{{ item.title }}
</p>
</div>
<div v-if="path.length > 0">
<div class="backButton">
<v-icon #click="swapPrevious()" class="arrow">fa-arrow-left</v-icon>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapGetters } from "vuex";
export default {
name: "Scan",
computed: {
...mapGetters(["getResourceHierarchy", "getIsDarkMode", "getFontSize"])
},
methods: {
swapComponent(item) {
this.path.push(item.title);
this.currentItem = item;
this.items = this.currentItem.items;
},
assignParent(children, parent) {
children.forEach(item => {
item.Parent = parent;
var parentTitle = "";
if (parent) parentTitle = parent.title;
if (item.items) {
this.assignParent(item.items, item);
}
});
},
swapPrevious() {
if (this.currentItem.parentId === null) {
this.items = this.initialItems;
this.path.pop(this.currentItem.title);
} else {
this.currentItem = this.currentItem.Parent;
this.items = this.currentItem.items;
this.path.pop(this.currentItem.title);
}
}
},
mounted: function() {
this.assignParent(this.items, null);
this.initialItems = this.items;
},
data: () => ({
currentItem: null,
path: [],
initialItems: [],
items: [
{
parentId: null,
id: 11,
title: "Location 1",
items: [
{
parentId: 11,
id: 4324,
title: "Row 1",
items: [
{
parentId: 4324,
id: 4355,
title: "Row 1.1",
items: [
{
parentId: 4355,
id: 64646,
title: "Row 1.2",
items: [
{
parentId: 64646,
id: 7576657,
title: "Row 1.3",
items: [
{
parentId: 7576657,
id: 8686,
title: "Row 1.4",
items: [
{
parentId: 8686,
id: 12313,
title: "Row 1.5",
items: [
{
parentId: 12313,
id: 234324,
title: "QR Code"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
})
};
</script>
<style lang="scss" scoped></style>

Two-Way Binding in Component Scope

Suppose I'm trying to make a simple questionnaire, where the user answers a list of questions.
new Vue(
{
el: "#app",
data:
{
questions:
[
{
id: 1,
name: "What is your favorite color?",
selectedId: 2,
choices:
[
{ id: 1, name: "red" },
{ id: 2, name: "green" },
{ id: 3, name: "blue" },
]
},
...
]
}
});
How do I go about making a question component with two-way binding. That is, if the user swaps their favorite color from green to red, by clicking on the respective input, the selectedId will automatically update. I'm not very clear on how v-model works within a component. Does it only have access to the components data? Also, I don't understand the difference between props/data.
There are lots of ways you can approach this, here's my attempt:
let id = 0;
Vue.component('question', {
template: '#question',
props: ['question'],
data() {
return {
radioGroup: `question-${id++}`,
};
},
methods: {
onChange(choice) {
this.question.selectedId = choice.id;
},
isChoiceSelected(choice) {
return this.question.selectedId === choice.id;
},
},
});
new Vue({
el: '#app',
data: {
questions: [
{
title: 'What is your favorite color?',
selectedId: null,
choices: [
{ id: 1, text: 'Red' },
{ id: 2, text: 'Green' },
{ id: 3, text: 'Blue' },
],
},
{
title: 'What is your favorite food?',
selectedId: null,
choices: [
{ id: 1, text: 'Beans' },
{ id: 2, text: 'Pizza' },
{ id: 3, text: 'Something else' },
],
},
],
},
});
.question {
margin: 20px 0;
}
<script src="https://rawgit.com/yyx990803/vue/master/dist/vue.js"></script>
<div id="app">
<question v-for="question of questions" :question="question"></question>
</div>
<template id="question">
<div class="question">
<div>{{ question.title }}</div>
<div v-for="choice of question.choices">
<input type="radio" :name="radioGroup" :checked="isChoiceSelected(choice)" #change="onChange(choice)"> {{ choice.text }}
</div>
<div>selectedId: {{ question.selectedId }}</div>
</div>
</template>