How to adjust text field reactivity in Vue.js - javascript

I have a simple text field in Vue.js:
new Vue({
el: '#app',
data: {
value: 'Test'
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="value" ref="input" />
<p>{{ value }}</p>
</div>
Is it possible to decrease the frequency of updating the value in the data model from 'onChange' to 'onBlur'?

v-model is just syntax sugar for =>
:value="modelValue" #input="modelValue = $event.target.value"
If you want something else, it's very easy to do. Just change the update side to onBlur, so =>
<input class="form-control
:value="value"
#blur="value = $event.target.value"
#input="value = $event.target.value"
>
The improved example code:
new Vue({
el: '#app',
data: {
value: 'Test'
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input
type="text"
:value="value"
#blur="value = $event.target.value"
ref="input"
/>
<p>{{ value }}</p>
</div>

Yes, you should Just add #blur event, and pass through it the value of the event
Then when this event gets triggered in methods, it will change the value of result to the input value...so the updating became only conditioned to blur of the input
new Vue({
el: '#app',
data: {
result: '',
value:''
},
methods:{
blo(e){
this.result = e
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="app">
<input type="text" #blur='blo(value)' v-model="value" />
<p>{{ result }}</p>
</div>
</div>

Related

Based on v-on:click, How to uncheck the checkbox values in Vuejs?

<div class="reser-productlist">RESET</div>
<div class="checkbox-alignment-form-filter">
<input type="checkbox" id="Coils" value="Coils" class="vh-product" v-model="checkedNames" />
<label class="productlist-specific" for="Coils">Cs</label>
</div>
<div class="checkbox-alignment-form-filter">
<input type="checkbox" id="Sheets" value="Sheets" class="vh-product" v-model="checkedNames" />
<label class="productlist-specific" for="Sheets">Sts</label>
</div>
Based on v-on:click, How to uncheck/reset the checkbox,
Basically i want to uncheck the checkboxes, When user click on the RESET button/label. Generally to do this do i need to use the v-model or id or for in label to target and trigger the reset functionality?
I think you can use below code.
<div class="reser-productlist" #click="reset">RESET</div>
<script>
export default
{
methods:{
reset()
{
this.checkedNames = '';
}
}
}
</script>
const App = new Vue({
el: '#app',
template: `<div>
<div class="reser-productlist" #click="reset">RESET</div>
<div v-for="product in products" class="checkbox-alignment-form-filter">
<input type="checkbox" :id="product" :value="product" class="vh-product" v-model="checkedNames" />
<label class="productlist-specific" :for="product">{{ product }}</label>
</div>
</div></div>
`,
data() {
return {
products: ['Coils', 'Sheets'],
checkedNames: [],
}
},
methods: {
reset() {
this.checkedNames = []
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.12"></script>
<div id=app>

VueJS: How to set model of an input without having it to be on the input

I want an input to have no value on it's element on the view side but underneath I want it to have a default value, here is some snippet to explain my point:
<input
class="form-control"
v-model="amount"
type="number"
step=".01"
min="0"
required>
</input>
I want amount to be 0 by default but not render 0 on the input, is this possible in vuejs? If the input[type="number"] = '', the value of the property is 0 and not ' '.
You can use a computed property with getter and setter. The getter can return an empty string if the value is zero...
new Vue({
el: 'main',
data: {
amount: 0
},
computed: {
formattedAmount: {
get () {
return this.amount || ''
},
set (value) {
this.amount = parseFloat(value) || 0
}
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.min.js"></script>
<main>
<input class="form-control" v-model="formattedAmount" type="number" step=".01" min="0" placeholder="Amount" required/>
<pre>amount = {{ amount }}</pre>
</main>
you can bind the model values
var myObject = new Vue({
el: '#app',
data: {
amount: 0
}
})
<!DOCTYPE html>
<html>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<body>
<div id="app">
<input class="form-control" v-model="amount" type="number" step=".01" min="0" required>
</input>
</div>
</body>
</html>

Checkbox click invalid data inside v-for loop

I would like to validate at least one need to check the checkbox.
I'm trying to validate when I clicked on checkbox through the loop.
When I checked one, the output is invalid return false in the first click. When I unchecked return true. But when I checked my sizes array data with vue-dev tools data is valid. I'm trying to find that bugs but I didn't find.
I don't know why.I would like to know that's why? Am I wrong?
new Vue({
el: '#app',
data: {
sizes:[
{id:1,name:'small',ischeck:false,price:0},
{id:2,name:'medium',ischeck:false,price:0},
{id:3,name:'large',ischeck:false,price:0}
],
newval:[]
},
methods: {
checkchanged(){
for(var i=0;i<this.sizes.length;i++){
console.log(this.sizes[i].ischeck);
}
}
}
})
<script src="https://unpkg.com/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<span v-for="size in sizes">
<input type="checkbox" v-model="size.ischeck" :value="size.ischeck"
#click="checkchanged">
<label>{{size.name}}</label>
<input type="text" :disabled="!size.ischeck" v-model="size.price">
</span>
</div>
You could do that using computed property which you call error and hide/show the error message according to that property value:
new Vue({
el: '#app',
data: {
sizes:[
{id:1,name:'small',ischeck:false,price:0},
{id:2,name:'medium',ischeck:false,price:0},
{id:3,name:'large',ischeck:false,price:0}
],
newval:[],
},
methods: {
checkchanged(){
for(var i=0;i<this.sizes.length;i++){
console.log(this.sizes[i].ischeck);
}
}
},
computed:{
error(){
for(var i=0;i<this.sizes.length;i++){
if(this.sizes[i].ischeck) return false;
}
return true;
}
}
})
<script src="https://unpkg.com/vue#2.5.17/dist/vue.js"></script>
<div id="app" style="display :flex;flex-direction: column;">
<div v-for="size in sizes">
<input type="checkbox" v-model="size.ischeck" :value="size.ischeck"
#change="checkchanged">
<label>{{size.name}}</label>
<input type="text" :disabled="!size.ischeck" v-model="size.price">
</div>
<div v-if="error" style="color:red">
there's an error !
</div>
</div>
Finally you don't need to that event #click="checkchanged" you can use #change="checkchanged" instead

Dynamically adding different components in Vue

I want to create a simple form builder with Vue where users click on buttons from a menu to add different form fields to a form. I know that if there was just one type of form field to add, I could do it with something like this (https://jsfiddle.net/u6j1uc3u/32/):
<div id="app">
<form-input v-for="field in fields"></form-input>
<button type="button" v-on:click="addFormElement()">Add Form Element</button>
</div>
<script type="x-template" id="form-input">
<div>
<label>Text</label>
<input type="text" />
</div>
</script>
And:
Vue.component('form-input', {
template: '#form-input'
});
new Vue({
el: '#app',
data: {
fields: [],
count: 0
},
methods: {
addFormElement: function() {
this.fields.push({type: 'text', placeholder: 'Textbox ' + (++this.count)});
}
}
})
But what if there's more than one type of form field (input, file, select, etc...)? I was thinking maybe build a different component for each type, but then how would I show multiple types of components in a single list of form elements?
Could I maybe create a component with children components of different types based on the data in the fields array?
Or is there a better way to go about this situation that I'm missing? I've just started learning Vue, so any help is appreciated!
Ok, so I looked into dynamic elements and managed to pull this together:
Vue.component('form-input', {
template: '#form-input'
});
Vue.component('form-select', {
template: '#form-select'
});
Vue.component('form-textarea', {
template: '#form-textarea'
});
new Vue({
el: '#app',
data: {
fields: [],
count: 0
},
methods: {
addFormElement: function(type) {
this.fields.push({
'type': type,
id: this.count++
});
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.min.js"></script>
<div id="app">
<component v-for="field in fields" v-bind:is="field.type" :key="field.id"></component>
<button type="button" v-on:click="addFormElement('form-input')">Add Textbox</button>
<button type="button" v-on:click="addFormElement('form-select')">Add Select</button>
<button type="button" v-on:click="addFormElement('form-textarea')">Add Textarea</button>
</div>
<script type="x-template" id="form-input">
<div>
<label>Text</label>
<input type="text" />
</div>
</script>
<script type="x-template" id="form-select">
<div>
<label>Select</label>
<select>
<option>Option 1</option>
<option>Option 2</option>
</select>
</div>
</script>
<script type="x-template" id="form-textarea">
<div>
<label>Textarea</label>
<textarea></textarea>
</div>
</script>
So instead of creating a new form-input component for each item in the fields array, I'm creating a new component that is associated with the correct component via the type property of the fields
You can pass the field object as props of your form-input component and make the type dynamic:
Vue.component('form-input', {
template: '#form-input',
props: ['field']
})
new Vue({
el: '#app',
data: {
fields: [],
inputType: '',
count: 0
},
methods: {
addFormElement(val) {
this.fields.push({type: val, placeholder: 'Textbox ' + (++this.count)});
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>
<div id="app">
<h3>Add form element</h3>
<select size="3" v-model='inputType' #click="addFormElement(inputType)">
<option value="text">Text</option>
<option value="checkbox">Checkbox</option>
<option value="radio">Radio</option>
</select>
<p>
<form-input v-for="field in fields" :field="field"></form-input>
</p>
</div>
<template id="form-input">
<div>
<label>{{ field.type }}</label>
<input :type="field.type" />
</div>
</template>
Based on the code from the answer, one could add dynamic content for each one of those form controls as well ( the full concept could be seen from the following site):
Vue.component('form-input', {
template: '#form-input'
, props: ['label','cnt']
});
Vue.component('form-select', {
template: '#form-select'
, props: ['label','cnt']
});
Vue.component('form-textarea', {
template: '#form-textarea'
, props: ['label','cnt']
});
new Vue({
el: '#app',
data: {
fields: [],
count: 0
}
, mounted() {
// fetch those from back-end
this.addFormElement('form-input','lbl', "form-input-content")
this.addFormElement('form-textarea','lbl', "form-textarea-content")
var select_cnt = [
{'value': 1, 'text': 'item-01'},
{'value': 2, 'text': 'item-02'}
]
this.addFormElement('form-select','some-label',select_cnt)
}
, methods: {
addFormElement: function(type,label,cnt) {
this.fields.push({
'type': type
, id: this.count++
, 'label':label
, 'cnt':cnt
});
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.min.js"></script>
<div id="app">
<component v-for="field in fields" v-bind:is="field.type" :key="field.id" :cnt="field.cnt" :label="field.label"></component>
</div>
<script type="x-template" id="form-input">
<div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<input type="text" :value="cnt"/>
</div>
</script>
<script type="x-template" id="form-textarea">
<div v-on:keyup.tab="this.document.execCommand('selectAll',false,null);">
<label>{{label}}</label>
<textarea :value="cnt"></textarea>
</div>
</script>
<script type="x-template" id="form-select">
<div>
<label>Select</label>
<select>
<option v-for="oitem in cnt" :value="oitem.value">{{oitem.text}}</option>
</select>
</div>
<div v-html="cnt"></div>
</script>

How to use v-model with multiple in a custom select component?

i have the following vue component
<template>
<div id="input-div">
<label v-if="label">{{ label }}</label>
<select :multiple="multiple" :value="value" #change="change($event.target.value)">
<slot></slot>
</select>
<div class="error"><slot name="error"></slot></div>
</div>
</template>
<script>
export default {
name: 'ha-select',
props: ['label', 'value', 'multiple'],
methods: {
change(value) {
this.$emit('input', value);
}
}
}
</script>
and since it is a select component i want it to be usable with v-model which works when the multiple attribute is not set but when i set multiple pass v-model an Array instead of appending the selected value to the Array, the array just gets replaced by the value of the current selected option. maybe it has something to do with the way i am emitting the input event. So how do i create a custom select component with multiple support?
I've modified the code slightly to use a local variable bound to the select with v-model and emit the bound value. This results in emitting the array of selected values when multiple is true.
console.clear()
const CustomSelect = {
template: `
<div id="input-div">
<label v-if="label">{{ label }}</label>
<select :multiple="multiple" v-model="selected" #change="$emit('input', selected)">
<slot></slot>
</select>
<div class="error"><slot name="error"></slot></div>
</div>
`,
name: 'ha-select',
props: ['label', 'value', 'multiple'],
data(){
return {
selected:this.value
}
},
}
new Vue({
el:"#app",
data:{
albums: []
},
components: {
CustomSelect
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app">
<custom-select label="Pink Floyd Albums" v-model="albums" :multiple="true">
<option value="1">Dark Side of the Moon</option>
<option value="2">Animals</option>
<option value="3">The Wall</option>
</custom-select>
<div>
Selected Albums {{albums}}
</div>
</div>

Categories