Need to make v-model dynamic - vuejs2

I have a questionnaire that has MANY questions. The questions are either an input or a true|false|n/a response. The following allows me to load the questions from the database BUT the v-model isn't working so the responses aren't showing
<div v-for="(q, idx) in questions" :key="idx">
<div v-if="q.type === 'input'">
<question-input :question="q.question" :name="q.name"
v-model="comp.vaf.vendor_info.disassembly['q.name']"> . </question-input>
</div>
<div v-if="q.type === 'boolean'">
<question-boolean :question="q.question" :name="q.name"
v-model="comp.vaf.vendor_info.disassembly['q.name']"> . </question-boolean>
</div>

Your q.name is a variable hence it should not be in single quote as it would be considered as an property directly rather than considering it as an object value.
Try as below =>
<question-boolean :question="q.question" :name="q.name"
v-model="comp.vaf.vendor_info.disassembly[q.name]">

Related

How to read json object in vuejs?

Following is my json object:
const faqs = [{'question1':'answer1'},{'question2':'answer2'}]
I am reading this in vuejs in for loop in div as
<div v-for="(value, name, index) in faqs" :key="index">{{ value}}::{{ name }}</div>
but I not getting the required result.
Please guide me what am I doing wrong?
Following is the console log:
Thank you,
Trupti
In this cycle you are iterating over the faqs array, that means, it goes over each contained object one by one. The cycle does not go into objects, for that, you need separate cycle.
In addition to that, your data are not well formed, try to transform them to following:
[{ question: "question 1", answer: "answer 1"}, {question: "question 2", answer: "answer 2"}]
After that you can do:
<div v-for="(value, index) in faqs" :key="index">{{ value.question}}::{{ value.answer }}</div>
This will yield result:
question 1::answer 1
question 2::answer 2
On the other hand if you really want to iterate over properties of contained objects, then you need to do something like:
<div v-for="(value, index) in faqs" :key="index">
<div v-for="(propValue, propName) in value">
{{propName}}::{{propValue}}
</div>
This will work for the data in the original form you have posted. You have first cycle, which goes through each object (question-answer pair) one by one and second nested cycle, which goes over properties of every object.

vue v-model does not seem to be working in modal

I am pretty new to vue, and am trying to use it in a bootstrap modal. The relevant div in the modal is as follows.
<div class="form-group row">
<label for="priceQCField" class="col-sm-2 col-form-label">Price<span class="red"> *</span></label>
<input type="number" step="0.01" class="form-control col-sm-4" id="priceQCField" name="priceQCField" min="0" v-model="job.price">
</div>
I read some other questions about vue returning strings rather than numbers, so I have converted the job.price to a number inside my method to call the modal
showPriceJob: function (job) {
this.job = job;
this.job.price = parseFloat(this.job.price);
$('#mdlPriceJob').modal('show');
},
However, job.price refuses to appear in the input field either as a string or a number. I know it is available to the modal as I can see it using <span>{{job.price}}</span>.
Can anyone advise me please?
Additional - I think it is a display issue - if I change the input field, the entry in the <span> changes
2nd update - initial table
<tr class="light-grey" v-for="job in jobs" v-on:click="viewJob(job)">
<td>{{job.id}}</td>
<td>{{job.customerName}}</td>
<td>{{job.description}}</td>
<td v-bind:class="job.dueDate | dateColour">{{job.dueDate | dateOnly}}</td>
<td>£{{job.price}} {{job.isEstimate | priceEstimated}}</td>
<td>{{job.delivery}}</td>
</tr>
Upd.
According to your comments to my answer you are using v-for and you can't use this.job within your method. You should give us more code to see the whole picture.
Upd.2
You have showed more code but I didn't see any v-for so I am confused. You can try to use something like this if job is a property of appData.jobs:
showPriceJob: function (job) {
this.appData.jobs.job = Object.assign({}, job);
this.appData.jobs.job = parseFloat(this.appData.jobs.job.price);
$('#mdlPriceJob').modal('show');
},
But I'm not sure about this because I don't see where job is declared.
Upd.3
Oh! Wait! You have this code:
data: appData.jobs, but data should be in this format:
data: function(){
return {
appData: {
jobs: [],
},
}
},
Or show me what is your appData.jobs variable is.

Scope a single input in Vue built from JSON

I am building a simple quiz with vuejs. I've been working in https://codepen.io/jasonflaherty/pen/NBaJLO on this. I am able to get the correct responses to the checked input, however, it is not scoped to this.input and cascades to all radio buttons. I tried to use bind class with:
<span class="" v-bind:class="{ 'badge badge-success' : isCorrect, 'badge badge-danger' : isWrong, 'showthis' : showIt }">{{response.correct}}</span>
and am currently using:
v-if="isCorrect"
v-if="isWrong"
However, it is the same issue with the scope bound to the same input vs all of them.
What am I missing in vue to make this distinction?
You need to track at the question level rather than the global level.
Here are a couple simple changes you can make. Notice the input changes for value and v-model and also the conditions for the correct/wrong spans. This creates a property, selection on each question to track the currently selected answer for this specific question.
<li v-for="response in question.responses">
<label class="form-check-label">
<input class="form-check-input" type="radio"
:key="index"
:name="question.group"
:value="response.text"
v-model="question.selection">
{{response.text}}
<span v-if="question.selection === response.text && response.correct ==='Correct!' ">
Correct
</span>
<span v-else-if="question.selection === response.text && response.correct !=='Correct!' ">
Wrong
</span>
</label>
</li>
You could clean it up some more by altering your data model. There is no reason to save the correct text in the data. You can simply have the answer as a property and determine the textual response based on the selection.
var quizquestions = {
questions: [
{
text: "Subtract 219 from 500.",
group: "qone",
responses: [281, 719, 218, -219],
answer: 281, // correct answer
selection: null, // for v-model to track selected
},
]
};

Returning $key in AngularFire 5

I have the following code that works with AngularFire 5:
export class NavigationComponent {
items: Observable<any[]>;
constructor(db: AngularFireDatabase) {
this.items = db.list('/pages', ref => {
let query = ref.limitToLast(100).orderByChild('sortOrder');
return query;
}).valueChanges();
}
}
But now need to return item.$key which apparently is no longer returned by default in AngularFire 5. I see mention in the migration guide of needing to "map" this, but can't seem to get the right syntax working on the above code.
Update: followed the advice below, and it seemed to have worked but there appears to be some difference still between the behavior between old and new.
<nav class="nav-standard">
<app-logo></app-logo>
<div class="nav-dropdown">
<ul *ngFor="let item of items | async | filter : 'parent' : '00000000-0000-0000-0000-000000000000'" class="nav-dropdown">
<li>
<a mat-button class="mat-button" href="{{item.path}}" data-id="{{item.key}}" target="{{item.target}}" title="{{item.tooltip}}" [attr.data-sort]="item.sortOrder" *ngIf="item.content; else elseBlock">{{item.menuText}}</a>
<ng-template #elseBlock>
<a mat-button class="mat-button" data-id="{{item.key}}" target="{{item.target}}" title="{{item.tooltip}}">{{item.menuText}}</a>
</ng-template>
<ul class="nav-dropdown-content">
<li *ngFor="let childItem of items | async | filter : 'parent' : item.key" class="">
<a class="mat-button" href="{{childItem.path}}" data-id="{{childItem.key}}" target="{{childItem.target}}" title="{{childItem.tooltip}}" [attr.data-sort]="childItem.sortOrder">{{childItem.menuText}}</a>
</li>
</ul>
</li>
</ul>
</div>
</nav>
The nested *ngFor never seems to fire, whereas before it did. It appears that items in the nested *ngFor is null ?? I found if I create another Observable in my component called childItems and assign duplicate logic to that, it works okay -- but to me that feels dirty and wrong. How can I get the data in the observable to persist long enough to use it in the nested *ngFor ?
item key information isn't 'free' anymore upon the new AngularFire API changes. Instead of use '.valueChanges()' to turn reference into Observable, you can use '.snapshotChanges()':
.snapshotChanges()
.map(changes => {
return changes.map(change => ({key: change.payload.key, ...change.payload.val()}));
})
from then on you can reference item key by using 'item.key' (notice that you cannot use '$key').

Vue - altering model arrays

I have a simple Vue template consisting of an object with two arrays (dummy/placeholders vs actual data).
data() {
var tableColumns = new Array();
tableColumns.push({"dummyValues": ["date 1", "date 2"], "csvValues": []});
var variables = {
"tableColumns": tableColumns
};
return variables;
}
<td v-for="(item, key, index) in tableColumns">
<span v-if="item.csvValues.length == 0" v-for="dummyValue in item.dummyValues">
{{dummyValue}} <br />
</span>
<span v-else v-for="value in item.csvValues">
{{value}} <br />
</span>
</td>
At first, I only have dummy values. Something happens along the way (I parse a CSV file) and I need to exchange the dummy data I've first rendered with actual values.
I thus append my real data to the real data array (csvValues) and hope the v-else will take care of it.
This doesn't work - why, is my approach wrong?
Apparently, Vue can't switch between two data sources (dummyValues and csvValues).
I had to use a third one, which now holds/cycles elements from either of the first two. So, instead of building my view from one or the other arrays, I'm popping/pushing stuff to my third array (renderingValues) and always iterating that one.
Want to render dummyValues?
- pop everything (previously csvValues) from renderingValues
- push everything from dummyValues to renderingValues
- iterate renderingValues