Vue js dynamic v-model for form which is rendered with v-for - dynamic

I have 1 check box group and 9 radio button groups, and i need v-model for each group but i do not know how to put 9 differed data properties there.
My data looks like this:
data() {
return{
servicesId: [],
personId: '',
incomeId:'',
extraIncomeId: '',
pdvId: '',
paymentId: '',
clientId: '',
cashRegisterId: '',
eBankingId: '',
}
}
In template is like this:
<div v-for="data in formData" :key="data.id">
<h5>{{data.question_text}}</h5>
<div class="form-check" v-for="text_o in data.question_options" :key="text_o.id">
<input class="form-check-input"
:type="data.question_type.type"
:value="text_o.id" :id="text_o.id"
v-model="[HERE GOES "9 "data props"]">
<label class="form-check-label" :key="text_o.id" :for="text_o.id"> {{text_o.option_text}
</label>
</div>
</div>
Here is part of (because it is long, i can post everything from it if you want)formData array:
{
"id": 1,
"question_type_id": 1,
"title": "new ent",
"question_text": "Planirate da se bavite:",
"created_at": "2021-10-12T13:42:17.000000Z",
"updated_at": "2021-10-12T13:42:17.000000Z",
"question_options": [
{
"id": 1,
"question_id": 1,
"option_text": "Uslugama",
"price": 40,
"created_at": "2021-10-12T13:44:40.000000Z",
"updated_at": "2021-10-12T13:44:40.000000Z"
},
{
"id": 2,
"question_id": 1,
"option_text": "Trgovinom",
"price": 60,
"created_at": "2021-10-12T13:46:53.000000Z",
"updated_at": "2021-10-12T13:46:53.000000Z"
},
{
"id": 3,
"question_id": 1,
"option_text": "Proizvodnjom",
"price": 80,
"created_at": "2021-10-12T13:47:22.000000Z",
"updated_at": "2021-10-12T13:47:22.000000Z"
}
],
"question_type": {
"id": 1,
"type": "checkbox",
"created_at": "2021-10-12T13:40:17.000000Z",
"updated_at": "2021-10-12T13:40:17.000000Z"
}
}
Thanks.

If you want your values to be a part of data, you can create an object that will contain your form data, like this:
data() {
return {
formValue: {
servicesId: [],
personId: "",
incomeId: "",
extraIncomeId: "",
pdvId: "",
paymentId: "",
clientId: "",
cashRegisterId: "",
eBankingId: "",
},
}
}
after adding that object, just add a name to your form data object like this:
formData: [
{
id: 1,
question_type_id: 1,
title: "new ent",
question_text: "Planirate da se bavite:",
created_at: "2021-10-12T13:42:17.000000Z",
updated_at: "2021-10-12T13:42:17.000000Z",
name: "servicesId", <-- modified part
question_options: [...]
}
]
and now you can use that name to dynamically access your formValue object which is a part of data:
<div v-for="data in formData" :key="data.id">
<h5>{{ data.question_text }}</h5>
<div
class="form-check"
v-for="text_o in data.question_options"
:key="text_o.id"
>
<input
class="form-check-input"
:type="data.question_type.type"
:value="text_o.id"
:id="text_o.id"
v-model="formValue[data.name]" <-- modified part
/>
<label class="form-check-label" :key="text_o.id" :for="text_o.id">
{{ text_o.option_text }}
</label>
</div>
</div>
Hope this approach helps you, you will have your values in data, they won't be there as separate properties, but they will be a part of a wrapper object named formValue

Related

Checking if something exists in json in Vue

I've got a json API that I'm using like this:
[{
"name": "Thing",
"id": 1234,
"total": 1,
"stock": [
{
"size": "Small",
"id": 1,
"count": 10
},{
"size": "Medium",
"id": 2,
"count": 5
},{
"size": "Large",
"id": 3,
"count": 5
}
]
}]
I'm looping over these in Vue, but want to check if anything exists in the 'stock' element outside of the v-for loop.
I can use v-if to check if the overall json exists, but can't seem to narrow it down to checking if the stock element contains anything.
Any pointers?
What about a v-if & v-else condition on the length of the stocks array? If the length is greater than zero we have stocks, so display them, else, display a message. Something like this.
Vue.component('your-component', {
template:
`
<div v-for="(item, i) in items" :key="i">
<p>{{ item.name }}<p>
<p>{{ item.id }}<p>
<div v-if="item.stock && item.stock.length > 0">
<p v-for="(stock, j) in item.stock" :key="j">
There'are {{ stock.count }} of size {{ stock.size }}.
<p>
</div>
<div v-else>
Ops... stocks not available.
</div>
</div>
`,
data () {
return {
items: []
}
},
created () {
fetch('your-api')
.then((res) => res.json())
.then((res) => { this.items = res })
}
})

Add dynamically data-bound text in Vue.js

My case must be weird, but I have a good for it.
Here's my situation:
I have a Vue app that renders a form based on a json.
For example, the JSON:
{
"fields": [{
"name": "firstName",
"title": "Name"
}, {
"name": "lastName",
"title": "Last Name"
}, {
"title": "Hello {{ firstName }}!"
}]
}
From that json, the final render has to be:
<input type="text" name="firstName" v-model="firstName" />
<input type="text" name="lastName" v-model="lastName" />
<p>Hello {{ firstName }}</p>
I'm able to render all of that, except for the <p> which is rendered as raw {{ firstName }} and not data-bound/reactive.
My question is:
How do I insert dynamic templates (can come from a Rest API) into the component, and make them have the full power of the mustache expressions.
The component will have something like
{...firstName field...}
<dynamic template will be added here and update whenever firstName changes>
Please let me know if I'm not too clear on this issue
Thank you!!!
Is this the sort of thing you're trying to do? I've created a dynamic component whose template is generated from a JSON string which is editable.
new Vue({
el: '#app',
data: {
componentData: {
firstName: 'Jason',
lastName: 'Bourne',
},
jsonString: `
{
"fields": [{
"name": "firstName",
"title": "Name"
}, {
"name": "lastName",
"title": "Last Name"
}, {
"title": "Hello {{ firstName }}!"
}]
}`
},
computed: {
template() {
const json = JSON.parse(this.jsonString);
return json.fields.map((s) => {
if ('name' in s) {
return `<input type="text" name="${s.name}" v-model="${s.name}">`;
}
return s.title;
}).join('\n');
},
componentSpec() {
return {
template: `<div>${this.template}</div>`,
data: () => this.componentData
};
}
}
});
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<textarea rows="16" cols="40" v-model.lazy="jsonString">
</textarea>
<component :is="componentSpec"></component>
</div>

Returning values in Vue template

I cannot get values in my template while i have the data, here is my code:
code
<template>
<div>
{{project}}
</div>
</template>
<script>
export default {
props: ['id'],
data() {
return{
project:[]
}
},
created(){
this.fetchProject();
},
methods:{
fetchProject(){
var self = this;
axios.post('/showprojectvue/' +self.id).then(res => {
self.project.push(res.data);
});
},
}
}
</script>
output
[ { "id": 33, "user_id": 2, "title": "kjfsdjowhd", "slug": "kjfsdjowhd", "body": "<p>khweihgtfihrwhtg</p>", "attachment": null, "projectclass": "sthrh", "budget": 36346, "deadline": "2018-08-24", "published": "n", "runing": "n", "payment_verified": "n", "created_at": "2018-08-05 03:43:16", "updated_at": "2018-08-05 03:43:16" } ]
i cannot use any of {{project.title}} or {{project['title']}}
How can I get out my data?
As your data is an array you need to use v-for to iterate over it.
<template>
<div v-for="obj in project">
{{obj.title}}
</div>
</template>
Example,
function callMe(){
var vm = new Vue({
el : '#root',
data : {
project : []
},
methods: {
ajaxCall(){
this.project=[{ "id": 33, "user_id": 2, "title": "kjfsdjowhd", "slug": "kjfsdjowhd", "body": "<p>khweihgtfihrwhtg</p>", "attachment": null, "projectclass": "sthrh", "budget": 36346, "deadline": "2018-08-24", "published": "n", "runing": "n", "payment_verified": "n", "created_at": "2018-08-05 03:43:16", "updated_at": "2018-08-05 03:43:16" }];
}
},
})
}
callMe()
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.11/dist/vue.js"></script>
<div id='root'>
<button type="button" #click="ajaxCall">Click ME</button>
<div v-for="obj in project">
Title: {{obj.title}}
<p>
Object:{{obj}}
</p>
</div>
</div>

Vue,js Display data from json

How to fetch the product name from the below result. I tried
<div class="card-divider">
{{ post.basic_info.prod_name }}
</div>
But it is not working
Many thanks
{
"name":"Test ProductCategory",
"updated":"2018-07-16 15:00:03",
"12":{
"basic_info":{
"prod_name":"Product name 1",
"status":"Active",
"image":""
},
},
"13":{
"basic_info":{
"prod_name":"Product name 2",
"status":"Active",
"image":""
},
}
}
Try this:
{{ post["12"].basic_info.prod_name }}
Your JSON have two same keys, so you will receive Product name 2 only, because, latter will replace previous key "12"
My suggestion, modify data to receive something like:
{
"name": "Test ProductCategory",
"updated": "2018-07-16 15:00:03",
"data": [
{
"basic_info": {
"prod_name": "Product name 1",
"status": "Active",
"image": ""
},
}, {
"basic_info": {
"prod_name": "Product name 2",
"status": "Active",
"image": ""
},
}
]
}
you can loop over data and get basic_info.prod_name then your html will be like:
<div class="card-divider" v-for="obj in post.data">
{{ obj.basic_info.prod_name }}
</div>

Vue component list 2 event handling

Struggling with how to use .sync when you render components from a list. How do I handle the event emitted in my component to update the parent?
Trying to update the categorySet.gradeCategory.predictionWeight in the input.
<category-set v-for="cat in categories" v-bind:key="cat.id" v-bind:category-set="cat"></category-set>
Vue.component('category-set', {
props: ['categorySet'],
template: ' <div class="form-group">\n' +
' <label for="gradeRange" class="col-sm-2 control-label">{{ categorySet.gradeCategory.gradeCategoryName }}</label>\n' +
' <div class="col-sm-1">\n' +
' <input id="gradeRange" class="form-control" type="number" v-bind:value.number="categorySet.gradeCategory.predictionWeight" \n' +
' step="0.5" v-on:input="$emit(\'input\', $event.target.value)" > \n' +
' </div>\n' +
' </div>'
});
Fiddle: https://jsfiddle.net/rhmiller/aq9Laaew/10971/
Personally, I would do it like the following:
The component is passed the array index and the item (cat), with the item you define the item within the component, then bind the input event which then emits the complete object back to the parent with its index, then the parent sets the item back into the data.
As the Final Exam item is nulled the gradeCategory property you need to handle/recover from that as your using it in the view. Also the label is the same in the parent, so prefer to use that else it would be null if you used the gradeCategory one.
Vue.component('categorySet', {
template: '#category-set',
props: ['data', 'index'],
data() {
return {
item: {
label: this.data.label,
showInSummary: this.data.showInSummary,
gradeCategory: Object.assign({
"gradeCategoryName": null,
"groupGradeWeight": 0.0,
"predictionWeight": null,
"id": this.data.id
}, this.data.gradeCategory),
id: this.data.id
}
}
},
methods: {
inputOccurred(e) {
this.$emit('on-change', this.item, this.index)
}
}
});
//
var vm = new Vue({
el: '#app',
data() {
return {
categories: [
{
"label": "Assignments",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Assignments",
"groupGradeWeight": 0.0,
"predictionWeight": null,
"id": 81
},
"id": 81
}, {
"label": "Reflections",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Reflections",
"groupGradeWeight": 10.0,
"predictionWeight": null,
"id": 82
},
"id": 82
}, {
"label": "Quizzes",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Quizzes",
"groupGradeWeight": 10.0,
"predictionWeight": 10.0,
"id": 83
},
"id": 83
}, {
"label": "Attendance \u0026 Participation",
"showInSummary": true,
"gradeCategory": {
"gradeCategoryName": "Attendance \u0026 Participation",
"groupGradeWeight": 0.0,
"predictionWeight": null,
"id": 84
},
"id": 84
}, {
"label": "Final Exam",
"showInSummary": true,
"gradeCategory": null,
"id": 92
}
]
}
},
methods: {
syncCategorie(value, index) {
this.categories[index] = Object.assign(this.categories[index], value);
}
}
});
<div id="app">
<category-set v-for="(cat, index) in categories" :key="cat.id" :data="cat" :index="index" #on-change="syncCategorie"></category-set>
<pre>{{ categories }}</pre>
</div>
<template id="category-set">
<div class="form-group">
<label for="gradeRange" class="col-sm-3 control-label">{{ item.label }}</label>
<div class="col-sm-1">
<input id="gradeRange" class="form-control" type="number" v-model="item.gradeCategory.predictionWeight" step="0.5" #input="inputOccurred">
</div>
</div>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.14/vue.min.js"></script>
Run the snippet your see it updates the parent fine.
You can just omit the v-on:input part when you add a .sync modifier.
:prop.sync="binding"
will effectively expands into:
:prop="binding" #update:prop="value => binding = value"
( : is just an abbreviation for v-bind: and # for v-on: )