prop.sync is not working with :value (vuejs) - vue.js

I have a made a custom "Select" component as well as an "Input" component. For my use case, it a certain object with "Preset" value is selected then I want the "Input" component to dynamically set the value to this Preset value. The parent component (below) has the child component "MegaSelect" (the custom select component) and "MegaCell" (custom input component)
<MegaSelect
:row="rowNum"
:col="0"
:options="frontTypes"
:displayValue="true"
:data.sync="data.frontType"
placeholder="Item type"
#change="typeChange"
></MegaSelect>
Here the "Select" component called "MegaSelect" is triggering typeChange (below)
typeChange() {
var presets = productData.getFrontType(this.data.frontType).presets
this.wPresets = presets ? presets.w : null
this.hPresets = presets ? presets.h : null
this.qtyPresets = presets ? presets.qty : null
}
typeChange will check if my selected object has a hardcoded "Preset" value. if it does, it will update the data of wPresets, hPresets and qtyPresets.
<MegaCell
:value="qtyPresets ? qtyPresets[0] : null"
:data.sync="data.qty"
dataType="Number"
:row="rowNum"
:col="4"
></MegaCell>
it will then dynamically update the :value of another custom "input" component called "MegaCell" which has a :prop.sync updating the "data" prop.
the MegaCell component has the following template
<template>
<div
class="mega-cell"
:class="{
selected: selected,
focussed: focussed,
outOfBounds: outOfBounds,
warn: warn
}"
#mousedown="mousedown"
>
<input ref="field" v-model="convertedDbValue" #focus="setFocus" #dblclick="setFocus" :placeholder="placeholder" />
</div>
</template>
I believe my mistake has something to do with the v-model and my computed: convertedDbValue's setter (below)
convertedDbValue: {
get: function() {
if (!this.data) return null
var fixedData = this.$utils.toFixedNumber(this.data / 25.4, 3)
var adjustedData = fixedData % 1 == 0 ? parseInt(fixedData) : fixedData
return this.dataType == 'Number' && this.unit == 'inch' ? adjustedData : this.data
},
set: function(value) {
if (this.dataType !== 'String') {
var val = this.unit == 'inch' ? this.$utils.toFixedNumber(value * 25.4, 3) : parseInt(value)
this.$emit('update:data', val)
} else {
this.$emit('update:data', value)
}
}
}
it's updating the data prop with a few adjustments to the inputted (number) value. how do i get the :value to dynamically change from the parent component to the child component and update the input value accordingly?

Related

q-input has value then only Rules will apply

If q-input has value != '' then only i want to apply the Rules like required 8 number maximum. In the below code it gives me the required input error even it's null.
<q-input
filled
name="landline"
label="Landline Phone Number"
v-model="user.landline"
placeholder="Landline Phone Number"
ref="landlinePhoneNumber"
type="number"
:maxlength="8"
:rules="[val => val!='' && val.length > 7 || 'Landline Required 8 digit']"
/>
Try to add prop lazy-rules.
By default, it's set to 'ondemand', which means that validation will be triggered only when the component’s validate() method is manually called or when the wrapper QForm submits itself. More info
You have to return true when the field is null first, then validate only if it's not null. Also, add the prop lazy-rules so that it only validates when the form field loses focus.
Here is how I did it in Vue 3, using composable and TypeScript. The form field component:
<q-input
class="q-mt-md"
filled
v-model="id_number"
label="ID Number "
type="text"
hint="Optional/Leave blank if not available"
lazy-rules
:rules="[(val) => isNumberBlankOrValid(val) || 'Invalid ID Number']"
/>
The method isNumberBlankOrValid called from the field above:
const isNumberBlankOrValid = (val: string) => {
if (val.length === 0) {
return true
}
return isValidNumber(val)
}
The isValidNumber for other fields that must be filled:
const isValidNumber = (val: string) => val && isNumeric(val)
The isNumeric method is a simple regex for validating numbers:
const isNumeric = (value: string) => {
return /^\d+$/.test(value)
}

How can I pass a value from v-select to method - it always stays the same as the default

I have a function I want to pass a value to in my Vue app using v-select.
v-select is populated from a data array 'chapters'.
I then want to use the selected id to pass to a function.
I have an empty data variable 'chapterIdFilter' in my data return which is set to a value of 1 - this pre-filters my vuetify data table
How can I pass the value of the id - chapterIdFilter - from my v-select dropdown to a function in my methods so I can filter the table with it?
The chapterIdFilter is always '1'
<v-select
:model="chapterIdFilter"
:items="chapters"
item-text="locale.en.title"
item-value="id"
label="Filter by Chapter"
#change="currentDataItems(chapterIdFilter)"
/>
Method:
currentDataItems (chapterIdFilter) {
console.log(chapterIdFilter)
return this.portals.filter(val => val.chapterId === parseInt(chapterIdFilter)) // this.portals.filter(val => val.chapterId === '1')
}
UPDATE:
So the code below works as desired but I am not sure it should or know why
currentDataItems (chapterIdFilter) {
console.log(chapterIdFilter)
this.chapterIdFilter = chapterIdFilter
return this.portals.filter(val => val.chapterId === parseInt(this.chapterIdFilter))
},
You should bind v-model directive to the data property and use it with this in your method :
<v-select
v-model="chapterIdFilter"
:items="chapters"
item-text="locale.en.title"
item-value="id"
return-object
label="Filter by Chapter"
#change="currentDataItems"
/>
method:
currentDataItems () {
console.log(this.chapterIdFilter)
return this.portals.filter(val => val.chapterId === parseInt(this.chapterIdFilter))
}

How to use the concatenate names of the elements/options in one function in vue-select

I have a project where I use many vue-select components.
My components:
...
<v-select ref="select_1" :options="options_1" #search:focus="maybeLoad('1')">
</v-select>
<v-select ref="select_3" :options="options_2" #search:focus="maybeLoad('2')">
</v-select>
<v-select ref="select_3" :options="options_3" #search:focus="maybeLoad('3')">
</v-select>
...
My method:
...
maybeLoad(name) {
// Vue.prototype.$options_select = 'options_' + name;
// const options_select = 'options_' + name;
return this.$options_select.length <= 0 ? this.load(name) : null
},
...
I was trying with Vue.prototype.$options_select or const options_select, but not working.
Error with Vue.prototype:
vue-select is empty.
Error with const options_select
TypeError: "this.$options_select is undefined; can't access its "length" property"
If I am using dedicated functions for every vue-select ... is working, every vue-select is filled with data from axios (with load() method).
Any ideas?
Found the solution:
...
maybeLoad(name) {
const options_select = 'options_' + name;
return this[options_select].length <= 0 ? this.load(name) : null
},
...

Angular5 data prepopulation one way binding not happening

I am using a parent component travelerInput that creates travelerListForm using model in my component and iterate it extracting travelerForm which is then passed to the nested child components using #Input:
for (let i = 1; i <= numberOfTravelers; i++) {
const tId = `${ptc}_0${i}`;
const Id = `${TravelerInput.pIndex++}`;
const traveler = new Traveler({passengerTypeCode: ptc, id: Id, tid: tId, names: [new Identity({
firstName: "",
middleName: "",
lastName: "",
title: "",
nameType: "native",
isDisplayed: false
})],
dateOfBirth: undefined ,
gender: "unknown",
accompanyingTravelerId: "",
accompanyingTravelerTid: ""
});
travelerList.push(traveler);
}
HTML
<div class="alpi-section col-xs-12 col-sm-12 col-md-12 col-lg-12"
*ngFor="let travelerForm of travelerListForm.controls; let tIndex = index;">
<o3r-simple-traveler-input
[config]="config.simpleTravelerInput"
[travelerForm]="travelerForm"
[index]="tIndex">
</o3r-simple-traveler-input>
Now we have a drop down in parent component with a list of travelers. The selected passenger in the drop down will have its information prepopulated in the form fields which are nested child components. I am using travelerForm which is iterated over travelerListForm in child components as #Input. On change of drop down I am binding the value of the passenger information to the corresponding index of travelerListForm which is also getting updated but on UI there is no update.
pickSelectedADTPassenger(adult:any, index: number){
this.selectedADTId= this.ADTTravelerId[adult];
this.travelerListForm.controls[index].value.names[0].firstName = this.selectedADTId.IDENTITY_INFORMATION.FIRST_NAME; //ASSISGNMENT
}
Have also tried using ngModel in the child component input field where I want the value to be prepopulated but it did not work:
<input type="text"
[(ngModel)]="travelerForm.controls.firstName.value"
class="form-control"
placeholder="FIRST NAME"
maxlength="52"
formControlName="firstName">
</div>
Please suggest.

How can I add 2 condition in one class vue.js 2?

My vue component is like this :
<template>
<a :class="'btn ' + [respond == 'responseFound' ? ' btn-yellow' : ' btn-default', type == 1 ? ' btn-block' : ' btn-xs center-block']">
...
</a>
</template>
I try like that, but it does not work?
You can use :class="[array, of, classes]" syntax:
<a :class="['btn', (respond === 'responseFound' ? 'btn-yellow' : 'btn-default'), (type === 1 ? 'btn-block' : 'btn-xs center-block')]">
As a bonus you don't have to worry about adding the leading spaces, Vue will handle it.
Just to keep things clean in view/template/markup, move your conditions to computed properties:
<template>
<a :class="['btn', getRespondClass, getTypeClass]">
</template>
<script>
export default {
data () {
return {
respond: '',
type: ''
}
},
computed: {
getRespondClass () {
return this.respond === 'responseFound' ? 'btn-yellow' : 'btn-default'
},
getTypeClass () {
return this.type === 1 ? 'btn-block' : 'btn-xs center-block'
}
}
}
</script>
Pretty sure the current showed answer says how you can add multiple classes on 1 condition. But if you want to have multiple conditions for your class added you can simply just do it like this:
:class="{'classname': condition_one && condition_two}"
Or you can do this:
:class="[ condition1 | condition2 ? 'className' : '']"
This checks for either of the conditions to be true. If you want to check for both replace | with &&. But if you have nothing in the else class, I think #Marnix's answer is cleaner.