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

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.

Related

Vue3 - print function result into p vs print function to css section inside html tag

let's say I have a very simple setup using data() and a function written in the methods part. With the function I'm returning a random number between 1 and 3, while the data contains an list of blog elements.
When displaying the result from randomNumber directly on the page using <p>{{randomNumber()}}</p> the value (1-3) get's printed. In my case I'm printing all posts from blogs using v-for on the parent div.
When however, trying to alter a css class with said number the number does not get printed. For this particular test I have made .g1, .g2 and .g3 with different style attributes. When inspecting the source code directly in the browser the .blog-thumb class has g{{randomNumber()}} as a second class.
i tried to call randomNumber() within the blogs item but I'm still unable to add the generated class to the css class section.
Thank you for your help or suggestions.
HTML:
<div class="col" v-for="blog in blogs" :key="blog.id">
<div class="blog-thumb g{{randomNumber()}}"> <!-- DOES NOT GET PRINTED -->
{{randomNumber()}} <!-- GETS PRINTED -->
<p class="date">{{ blog.date }}</p>
</div>
<h2>{{blog.title}}</h2>
<p>{{blog.content}}</p>
</div>
Vue:
methods : {
randomNumber : function(){
return Math.floor(Math.random() * 3+1);
}
},
data() {
return{
blogs: [
{
id: '1',
title: 'Amet consectetur adipisicing',
date: 'March 3rd 2022',
content: 'Lorem ipsum...'
},
{...}
]
}
}
after fiddling with it for quite a while today I found this solution:
I changed the function to return a complete classname (in this case, g with a random number between 1 and 3)
randomNumber : function(){
return 'g' + Math.floor(Math.random() * 3+1);
}
in the html part I added the v-bind to the class and passed the function (v-bind:class="randomNumber()")
<div class="col" v-for="blog in blogs" :key="blog.id">
<div class="blog-thumb" v-bind:class="randomNumber()">
<p class="date">{{ blog.date }}</p>
</div>
<h2>{{blog.title}}</h2>
<p>{{blog.content}}</p>
</div>
with this, now every col blog-thumb class got another generated class added to it.

Vue/Vuelidate: Dynamically show required star (*) based on requiredIf

I'm creating a dynamic re-usable vue component that wraps a text input and includes the vuelidate validation stylings, etc.:
<template>
<div class="form-group" :class="{'form-group--error': validator.$error}">
<label>{{ label }}<span v-if="validator.$params.required">*</span></label>
<input type="text v-model="validator.$model" />
<div class="error" v-if="validator.$error && !validator.required">* This field is required</div>
</div>
<template>
<script>
export default {
name: "FormTextField",
props: ["validator", "label"]
}
</script>
(validator prop is $v from parent)
The problem I have is trying to show the <span>*</span> dynamically based on if the field is required. This currently works (v-if="validator.$params.required") as long as I only specify the required validator:
fieldName: {
required: required
}
Now, I need to instead declare my validation like this:
fieldName: {
required: requiredIf( ... )
}
The question is how to access the result of the requiredIf function? validator.$params.required will always be true since it's just checking if the param is there. And validator.required is the status of the validation, not the result of the requiredIf call to see whether it SHOULD be required or not.
Any suggestions on how I can show the required star dynamically based on vuelidate state?
Instead of validator.$params.required, check validator.required, which is only defined when there's a required or requiredIf validator rule applied. The value of validator.required is true when the field is missing, or false otherwise.
When the field is optional (has no required/requiredIf rule), the validator.required property does not exist, so we can't use v-if="!validator.required". Instead, explicitly compare validator.require to false:
<label>{{ label }}<span v-if="validator.required === false">*</span></label>
<div class="error" v-if="validator.$error && validator.required === false">* This field is required</div>
demo

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
},
]
};

vue.js method can't access variable from data object with multiple rows

I am currently learning vue.js and having trouble accessing data in the methods.
data is loaded and set as a global variable (for now, this will probably change but not part of the problem now i think)
through ajax call this data is received:
data":[{"itemId":"58646f066803fa62388b4573","color":"#ffb878","name":"test1","startDate":"04/24/2017","work":"9.25"},{"itemId":"58646f066803fa62388b4572","color":"#ffb878","name":"test2","startDate":"04/24/2017","work":"4.25"},{"itemId":"58646f066803fa62388b4571","color":"#a4bdfc","name":"test3","startDate":"05/01/2017","work":"24.00"}]
which is set as a global (variable data is set outside of the functions) with:
...success: function (jsonObj)
{
data['item'] = jsonObj.data
....
now for the vue part:
var app = new Vue({
el:'#canvas',
data: {
items: data['item']
},
methods: {
moveItem: function(){
console.log("new date: "+this.startDate);
}
}
})
the html:
<div v-for="row in items" class="entirerow" v-bind:id="'row'+row.itemId">
<div class="itemrow">{{ row.name }}</div>
<div class="itemrow"><input type="text" v-model="row.startDate" #change="moveItem"></div>
<div class="itemrowlast">{{ row.work }}</div>
</div>
this nicely shows 3 rows with the correct data in each row. So far so good. But now if I change something in the input value the method moveItem is triggered but states "new date: undefined" in the console.log
I've tried console.log("new date: "+this.items.startDate) as well but no cigar and then it would seem the method wouldn't know which row is handled.
How can I access the correct data in the method, so from a certain row in the loop?
Thanks!
You refer to data object in method (this.startDate) not to item
moveItem: function(){
console.log("new date: "+this.startDate);
}
You can change your code like this
template
#change="moveItem(row)"
script
moveItem: function(row){
console.log("new date: " + row.startDate);
}

What is the best approach for tracking any change in model in aurelia?

I have simple requirement Let's take an example
EX1:
In My View I have two Input fields
First Name and Last Name and one button submit to save first name and Last name.
Now I want that my submit button gets enabled only when there is any change in first name and last name value.
EX2:
In My View I have two Input fields
First Name and Last Name and one button submit to save first name and Last name.
Now here first name and last name having value from my view-model. if i change anything for first name and last name my submit button gets enabled, now again if i put previous value for first name and last name my submit button gets disabled.
<template>
<form role="form" submit.delegate="SaveDetail()" validate.bind="validation">
<div class="form-group">
<label>First Name</label>
<input type="text" value.bind="firstName" class="form-control">
</div>
<button class="btn btn-success" type="submit" disabled.bind="!validation.result.isValid">save</button>
</form>
</template>
import {inject} from 'aurelia-framework';
import {Validation} from 'aurelia-validation';
#inject(Validation)
export class ChildRouter {
firstName: string = 'pranay';
validation;
constructor(Validation) {
var self = this;
self.validation = Validation.on(self)
.ensure('firstName')
.isNotEmpty()
.hasMinLength(3)
.hasMaxLength(10)
.isNotEqualTo(self.firstName);
}
SaveDetail() {
var self = this;
self.validation.validate()
.then(() => {
alert(self.firstName);
});
}
}
Please let me know the best approach for this type of scenario.
Try to track 'dirty' values with validation rule isNotEqualTo(oldValue) and just check if result is valid.
<button disabled.bind="validation.result.isValid"></button>
UPDATE: But when model is refreshed, like after saving, validation object should be re-initialized too. Also for earlier versions it was advised to call this.formValidation.destroy();, not sure if it is needed now.