VueJs2 checkbox v-bind:true-value is not working - javascript

I have created a vuejs2 app using vue-cli. I'm trying to bind dynamic value for checkbox as vuejs documentation said: value binding. But its giving me undefined. If I don't bind vlaue its giving me true or false. This is my ValueBinding.vue component.
<template>
<div id="input">
<p> Selected value for smoking: {{ smoking }} </p>
<input v-model="smoking" v-bind:true-value="Y" v-bind:false-value="N" type="checkbox">
<label>No Smoking</label>
<br>
<button #click="submit">Submit</button>
</div>
</template>
<script>
export default {
name: 'value-binding',
data() {
return {
smoking: ''
}
},
methods: {
submit() {
console.log(this.smoking) //shows undefined
}
}
}
</script>
I'm new to vuejs. Thanks in advance.

When you use v-bind, it dynamically bind one or more attributes to an expression. In your case when you do
v-bind:true-value="Y"
It will try to find a data attribute: Y in vue instance, as you have not defined any such attribute, it will become undefined.
If you just want to true-value as "Y" and false-value as "N", do follwing:
<input v-model="smoking" true-value="Y" false-value="N" type="checkbox">

Related

Use parent slot variables in Vue template slot

I have a simple FormComponent:
<template>
<form>
<fieldset>
<slot />
</fieldset>
<span v-if="!isEditing" #click="edit()">Edit</span>
</form>
</template>
<script>
export default {
data () {
return {
isEditing: false,
}
},
methods: {
edit (state) {
this.isEditing = !this.isEditing
}
}
}
</script>
And when I use the component:
<FormComponent>
<input value="Man" type="text" :disabled="!isEditing">
</FormComponent>
The input field are correctly slotted into the component but the :disabled="!isEditing" from the slot isn't reacting to the change of isEditing in the FormComponent.
The Vue documentation is pretty good, but it doesn't cover each edge case.
The component with the <slot></slot> tag has to bind the data onto an attribute on the <slot> tag, like a prop:
<slot :isEditing="isEditing"></slot>
Then when you render that slotted component, Vue creates and exposes an object containing all of the bound data, with each attribute having a property on that object.
Access the object by adding an expression to the v-slot directive in this format:
<FormComponent v-slot:default="slotProps">
(Or use the alias # as in #default="slotProps".) You can access individual properties like isEditing via that object, like slotProps.isEditing:
<FormComponent #default="slotProps">
<input value="Man" type="text" :disabled="!slotProps.isEditing">
</FormComponent>
Here's the more common (and versatile) <template> syntax:
<FormComponent>
<template #default="slotProps">
<input value="Man" type="text" :disabled="!slotProps.isEditing">
</template>
</FormComponent>
You can also destructure slotProps for more direct access to the properties:
<FormComponent>
<template #default="{ isEditing }">
<input value="Man" type="text" :disabled="!isEditing">
</template>
</FormComponent>

Create a two-way binding in vue.js between an array and multiple text inputs

My data is stored in an array. For each array item, there should be a text input in the form. When the user types into one of the text inputs, the array should be updated with the new values.
<div class="form-group" v-for="synonym in row.synonyms">
<input type="text" class="form-control" v-model="synonym" />
</div>
Here's a fiddle: https://jsfiddle.net/eywraw8t/122210/
The idea is when you type into one of the textboxes, the array value (shown below in that fiddle) should also update, but it doesn't.
Upon inspecting the console, you would find the following error:
You are binding v-model directly to a v-for
iteration alias. This will not be able to modify the v-for source
array because writing to the alias is like modifying a function local
variable. Consider using an array of objects and use v-model on an
object property instead.
Meaning, we need to give v-model access to a direct reference to the synonym and its index:
new Vue({
el: "#app",
data: {
row: {
synonyms: [
"abc",
"def",
"ghj",
]
}
},
methods: {
}
})
body {
font-family: 'Exo 2', sans-serif;
}
#app {
margin: auto;
}
<div id="app">
<h2>Items</h2>
<div class="form-group" v-for="(synonym,i) in row.synonyms">
<input type="text" class="form-control" v-model="row.synonyms[i]" />
</div>
<br>
<h3>
The text below should change if yout type inside the textboxes:
</h3>
<p>
{{ JSON.stringify(row)}}
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
The correct way to do it is to use an index, which vue.js provides in loops:
<div class="form-group" v-for="(synonym, index) in row.synonyms">
<input type="text" class="form-control" v-model="row.synonyms[index]" />
</div>
https://jsfiddle.net/m14vd89u/1/
This is the recommended way that Vue.js wants you to do it by using an index (synonym, index):
https://v2.vuejs.org/v2/guide/list.html
<div class="form-group" v-for="(synonym, index) in row.synonyms">
<input type="text" class="form-control" v-on:blur="onItemsChanged(synonym)" v-model="row.synonyms[index]" />
</div>
If you wanted to do it another way you could introduce a method v-on:blur:
new Vue({
el: "#app",
data: {
row: {
synonyms: [
"abc",
"def",
"ghj",
]
}
},
methods: {
onItemsChanged (synonym) {
// do something with array
}
}
})

Vue - passing v-model from child to parent in v-for loop

I'm building a form builder in Vue which allows users to add/remove various types of input. My method so far is to have a template component for each input type, then when a user selects that input type I push it into an array on the parent component to loop over and display.
However, I also need to pass the value of the input up to the parent (and store it in the input type="hidden" element), so I'm emitting an event in the child component and catching it in the parent. My problem is that the value of labelText gets updated identically for every input type="hidden" at once when I type, rather than individually. I can't work out what I'm missing?
Text input template
<template>
<div id="TextInput">
<input type="text" placeholder="Question" class="form__input_label" #input="sendLabelUp($event.target.value)" />
<input type="text" placeholder="Test placeholder" />
<slot name="removeField"></slot>
<slot name="hiddenInputs"></slot>
</div>
</template>
<script>
export default {
name: 'TextInput',
methods: {
sendLabelUp: function(val) {
this.$emit('input', val);
},
},
};
</script>
Parent template (just including the part I think is relevant)
<transition-group name="form__input_list" tag="div">
<component :is="input.type" v-for="(input, index) in inputs" v-bind="input" :key="input" v-model="labelText" class="form__input">
<div slot="removeField">
<a class="btn btn--tertiary sml-push-top-half" #click="removeField(index)">Remove</a>
</div>
<div slot="hiddenInputs">
<!-- Hidden inputs used to store question config -->
<input type="hidden" :name="`pages[0]questions[${index}]type[${input.type}]label[${labelText}]`" />
</div>
</component>
</transition-group>
<script>
export default {
name: 'InputGenerator',
components: {
TextInput,
TextArea,
NumberInput,
LikertScale,
},
data() {
return {
inputs: [],
dropdownActive: false,
labelText: '',
};
},
};
</script>

Dynamic V-model name in a v-for loop Vue 2

I am developing an application and I am using Vue 2 as the javascript framework,
inside a v-for loop I need the counter of the loop to be bound to the v-model name of the elements, this my code:
<div v-for="n in total" class="form-group">
<input type="hidden" id="input_id" :name="'input_name_id[' + n + ']'" v-model="form.parent_id_n" />
</div>
I need n to be the counter of the loop, for example for the first element it should be:
<div class="form-group">
<input type="hidden" id="input_id" :name="'input_name_id[1]" v-model="form.parent_id_1" />
</div>
the name attribute binding works but I have no idea how to get the v-model working as well?
To use v-model with form.parent_id[n]:
form should be a data property.
form.parent_id should be an array.
Then you can do the following:
<div id="demo">
<div v-for='n in 3'>
<input v-model="form.parent_id[n]">
</div>
<div v-for='n in 3'>
{{ form.parent_id[n] }}
</div>
</div>
by having a vue instance setup like:
var demo = new Vue({
el: '#demo',
data: {
form: {
parent_id: []
}
}
})
Check this fiddle for a working example.
Another way achieve this is using bracket notation of accessing object property.
<div v-for="n in total" class="form-group">
<input type="hidden"
id="input_id"
:name="'input_name_id[' + n + ']'"
v-model="form['parent_id_' + n ]" />
</div>
Repeated text filed 10 times and separated v-model for each
<v-text-field
v-for="(n,index) in 10"
:key="index"
v-model="pricing.name[n]"
color="info"
outline
validate-on-blur
/>
storing data
data() {
return {
pricing:{
name: [],
}
}
When you modify an Array by directly setting an index (e.g. arr[0] = val) or modifying its length property. Similarly, Vue.js cannot pick up these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience method arr.$set(index, value) which is syntax sugar for arr.splice(index, 1, value).
this code worked for me:
HTML
<input type="number" #input="updateValue($event, i, 'pci')" :value="form.neighbours[i].pci" />
JS
updateValue(event, i, key) {
const neighbour = {...this.form.neighbours[i]};
neighbour[key] = event.target.value;
this.form.neighbours.splice(i, 1, neighbour)
}
Assuming input_name_id is a string, What you need to do is :name="'input_name_id' + n"
Here is a working solution

Creating a Dynamic Form in a Aurelia View

Problem Overview
I have a controller with a view model which contains initially an empty array which will be used for storing 'Test Inputs'. I want to provide the user a button to add a new Test Input on the form which adds a new Test Input object to the array and displays the fields needed to edit its properties.
This works when the button is pressed for the first time (but with incorrect binding) but fails to create additional form elements when pressed again.
The Controller with View Model
import {inject} from 'aurelia-framework';
import {HttpClient, json} from 'aurelia-fetch-client';
import {Router} from 'aurelia-router';
import 'fetch';
import toastr from 'toastr';
#inject(HttpClient, Router)
export class create {
constructor(http, router) {
this.vm = {
test: {
id: 0,
description: "",
testOutput: {
id: 0,
valueType: "",
value: ""
},
testInputs: []
}
};
}
}
The user will be able to add a Test Input to the array by pressing a button which delegates to this function:
addTestInput() {
this.vm.test.testInputs.push({
argumentName: "",
valueType: "",
value: ""
});
}
This function pushes to the Test Inputs array in my view model object a new testInput object.
View
In my view I have added a repeat for binding for each object in the TestInputs array. The loop is intending to create the form elements for editing the properties of each Test Input object in the TestInputs array.
<p if.bind="vm.test.testInputs.length === 0">This test has no inputs. Click the button below to add one.</p>
<template if.bind="vm.test.testInputs.length > 0" repeat.for="testInput of vm.test.testInputs">
<div class="form-group">
<label for="testInputArgumentName${$index}">Argument Name</label>
<input value.bind="testInput.argumentName" type="text" class="form-control" id="testInputArgumentName${$index}" placeholder="Argument Name">
</div>
<div class="form-group">
<div class="form-group">
<label for="testInputValueType${$index}">Expected Value Type</label>
<select class="form-control" value.bind="testInput.valueType">
<option repeat.for="valueType of valueTypeList" value.bind="valueType">${valueType}</option>
</select>
</div>
</div>
<div class="form-group">
<label for="testInputValue${$index}">Expected Value</label>
<template if.bind="testInput.valueType === 'Boolean'">
<select class="form-control" value.bind="testInput.valueType">
<option>true</option>
<option>false</option>
</select>
</template>
<template if.bind="testInput.valueType !== 'Boolean'">
<input value.bind="testInput.value" type="text" class="form-control" id="testInputValue${$index}" placeholder="Expected Value">
</template>
</div>
</template>
<button click.delegate="addTestInput()" type="submit" class="btn btn-success">Add Test Input</button> <button type="submit" class="btn btn-success">Create Test</button>
When I first press the Add Test Input button the form elements are added to the page as expected. However if I press the button again the additional from elements for the new object added to the array are not created.
Also the fields seem to be binding to the local loop variable testInput rather than the specific object in the array.
Attempted Solutions
I have had a go using the suggestions at:
Blog Post on Dynamic Forms in Aurelia
Two Way Binding Array in Aurelia
Aurelia Gitter Chat Log - Help
from jsobell
But they don't seem to have worked for me. Anyone have any ideas?
Your problem is simple. You cannot use if and repeat on the same element. Also in your case are redundant with the p on the first line.
Simple do this:
<template repeat.for="testInput of vm.test.testInputs">
...
</template>
You can find more info here

Categories