How can i make a click event on v-select? - javascript

I am using vue-select and I wanna make a click event when i select a item from the select list. I tried with #change="changedValue" #selected="changedLabel" but that does not works for me.
Vue select
<v-select placeholder="Add administrator" class="form-control-select" label="displayName" :options="items"></v-select>
Does anyone know how to trigger an event? Thanks

Since you did not provide a link to the component library you are using I'll assume you are using vue-select.
A quick look trough its source shows the component has an onChange prop which is called when the selected value changes and defaults to emitting the input event.
You can simply attach your changedLabel to #input:
Vue.component('v-select', VueSelect.VueSelect)
new Vue({
el: '#app',
data: {
items: [
'foo',
'bar'
],
selected: null
},
methods: {
changedLabel(event) {
this.selected = event;
}
}
})
<script src="https://unpkg.com/vue-select#2.4.0/dist/vue-select.js"></script>
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<v-select
placeholder="Add administrator"
class="form-control-select"
label="displayName"
:options="items"
#input="changedLabel"
></v-select>
<span>{{ selected }}</span>
</div>

Related

v-model on input change is heavy on performance

So I have a page rendering a v-list based on an array like so :
<v-list-tile v-for="item in array">
{{item}}
</v-list-tile>
and a dialog with a v-text-field :
<v-dialog>
<v-text-field v-model="myInput">
</v-text-field>
</v-dialog>
For now it's pretty normal.
But with a performance test, I saw that for every event triggered by a change on myInput model (like a key press) the v-for is also triggered re-rendering the list when they are actually not related.
On my huge array, it's a serious problem and make the UI really laggy. I think it's a normal behavior for a vuejs application, but I was wondering if I could precisely tell wish element to check for re-rendering.
I tried some v-if statements but it didn't do the trick.
I hope that there is an answer to that, i guess i'm missing something.
If you want to test what i'm talking about here is a ready to go html file, please debug it with your debug console, you will see a [vue warn] message of the duplicated key attesting of the fact that the v-for is indeed called for every key press.
Imagine now if the array (here items) is way bigger than that, and wrapped into complex components, making that call is just too heavy on performance when we are just aiming to change the "myInput" value.
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{data}}
<ul>
<li v-for="item in items" :key="item">
{{ item.message }}
</li>
</ul>
<input v-model="data"></input>
</div>
</body>
<script>
new Vue({
el: '#app',
data: () => ({
data: '',
items: [{
message: 'Foo'
},
{
message: 'Bar'
}
]
})
})
</script>
</html>
Here's a codepen showing the inner loop in its own component
Codepen.io
I've added Date.now() after items[x].message list items to show when the list is being rerendered.
In case codepen ever goes down:
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.10/dist/vue.js"></script>
</head>
<body>
<div id="app">
Main vue: {{data}}
<loop-component :data="loopdata"></loop-component>
<input v-model="data"></input>
<input v-model="loopdata"></input>
</div>
<script>
Vue.component('loop-component', {
props: ['data'],
data() {
return {
items: [
{message: 'Foo'},
{message: 'Bar'}
]
}
},
template: `
<div>
Loop component: {{ data }}
<ul>
<li v-for="(item, index) in items" :key="index">
{{ item.message + ' Date.now(): ' + Date.now() }}
</li>
</ul>
</div>
`
});
let app = new Vue({
el: '#app',
data: () => ({
data: '',
'loopdata': '',
items: [
{message: 'Foo'},
{message: 'Bar'},
]
}),
});
</script>
</body>
</html>
Try using .lazy modifier to sync after change events.
<input v-model.lazy="data"></input>
https://v2.vuejs.org/v2/guide/forms.html#lazy
EDIT
#IVO GELOV is right, when a component changes, this re-render. The solution is split your component into several child components.
https://v2.vuejs.org/v2/guide/reactivity.html
This is a code using slots to make it look like your example.
HTML
<div id="app">
<new-component>
<ul>
<li v-for="item in items" :key="item">
{{ item.message }}
</li>
</ul>
</new-component>
</div>
Javascript
Vue.component('new-component', {
data: () => {
return {
data: ''
}
},
template: `
<div>
<div>{{ data }}</div>
<slot></slot>
<input v-model="data"></input>
</div>`
})
new Vue({
el: '#app',
data: () => ({
items: [{
message: 'Foo'
},
{
message: 'Bar'
}
]
})
})
Since Vue 2.0+ whenever a change is detected - the whole component is re-rendered. If you want to avoid that - split your component into several child components.
Your example does not prove your point - the fact that there is a warning about duplicate keys inside the v-for does not mean that v-for is re-evaluated on each keypress. To confirm my statement - just change your code like this:
<li v-for="(item,idx) in items" :key="idx">
Now there is no warning.

How to set default value on dynamic input fields in Vue.js?

I have created a dynamic input fields but the problem is that I don't know how to set default values on that dynamic fields for example number "1". Can anyone help me with that? Thanks
Here is my example
new Vue({
el: '#app',
data: {
result: [],
array: [{
id: 1
}, {
id: 2
}, {
id: 3
}]
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div v-for="(item, index) in array" :key="item.id">
<input type="number" :id="item.id" v-model="result[index]">
<br>
</div>
<span>Result: {{ result }}</span>
</div>
As Vue js is reactive you can simply set initial value in result
new Vue({
el: '#app',
data: {
result: ["1","1","1"],
array: [{
id: 1
}, {
id: 2
}, {
id: 3
}]
}
})
According to the official documentation,
v-model will ignore the initial value, checked or selected attributes
found on any form elements. It will always treat the Vue instance data
as the source of truth. You should declare the initial value on the
JavaScript side, inside the data option of your component.
I think it is a design decision of Vue to use the benefit of Vue instance’s reactive system rather than listening to DOM updates when such attributes are updated.
So you can put directly your default values into the result array, here's the updated working jsfiddle.

Input-fields as components with updating data on parent

I'm trying to make a set of components for repetitive use. The components I'm looking to create are various form fields like text, checkbox and so on.
I have all the data in data on my parent vue object, and want that to be the one truth also after the user changes values in those fields.
I know how to use props to pass the data to the component, and emits to pass them back up again. However I want to avoid having to write a new "method" in my parent object for every component I add.
<div class="vue-parent">
<vuefield-checkbox :vmodel="someObject.active" label="Some object active" #value-changed="valueChanged"></vuefield-checkbox>
</div>
My component is something like:
Vue.component('vuefield-checkbox',{
props: ['vmodel', 'label'],
data(){
return {
value: this.vmodel
}
},
template:`<div class="form-field form-field-checkbox">
<div class="form-group">
<label>
<input type="checkbox" v-model="value" #change="$emit('value-changed', value)">
{{label}}
</label>
</div>
</div>`
});
I have this Vue object:
var vueObject= new Vue({
el: '.vue-parent',
data:{
someNumber:0,
someBoolean:false,
anotherBoolean: true,
someObject:{
name:'My object',
active:false
},
imageAd: {
}
},
methods: {
valueChange: function (newVal) {
this.carouselAd.autoOrder = newVal;
}
}
});
See this jsfiddle to see example: JsFiddle
The jsfiddle is a working example using a hard-coded method to set one specific value. I'd like to eighter write everything inline where i use the component, or write a generic method to update the parents data. Is this possible?
Minde
You can use v-model on your component.
When using v-model on a component, it will bind to the property value and it will update on input event.
HTML
<div class="vue-parent">
<vuefield-checkbox v-model="someObject.active" label="Some object active"></vuefield-checkbox>
<p>Parents someObject.active: {{someObject.active}}</p>
</div>
Javascript
Vue.component('vuefield-checkbox',{
props: ['value', 'label'],
data(){
return {
innerValue: this.value
}
},
template:`<div class="form-field form-field-checkbox">
<div class="form-group">
<label>
<input type="checkbox" v-model="innerValue" #change="$emit('input', innerValue)">
{{label}}
</label>
</div>
</div>`
});
var vueObject= new Vue({
el: '.vue-parent',
data:{
someNumber:0,
someBoolean:false,
anotherBoolean: true,
someObject:{
name:'My object',
active:false
},
imageAd: {
}
}
});
Example fiddle: https://jsfiddle.net/hqb6ufwr/2/
As an addition to Gudradain answer - v-model field and event can be customized:
From here: https://v2.vuejs.org/v2/guide/components.html#Customizing-Component-v-model
By default, v-model on a component uses value as the prop and input as
the event, but some input types such as checkboxes and radio buttons
may want to use the value prop for a different purpose. Using the
model option can avoid the conflict in such cases:
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean,
// this allows using the `value` prop for a different purpose
value: String
},
// ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>
The above will be equivalent to:
<my-checkbox
:checked="foo"
#change="val => { foo = val }"
value="some value">
</my-checkbox>

vue2 list of form elements

I have a bunch of fields that I want to display as a long form, with each field allowing the user to select from a list of values for that field.
So the basic thing looks like this:
Vue.component('master-field', require('./Vue/MasterField').default);
new Vue({
store,
el: '#app',
computed: {
sourceFields: function () {
return store.getters.visibleSource
}
}
})
then in the page, it does this to spit out the fields one by one, using the sourceFields data:
<div id="app">
<div class="container-fluid">
<master-field v-for="item in sourceFields" :key="item.id"></master-field>
</div>
</div>
How can I access the item.id from within the master-field component? If I try to do a console.log(item.id) from the mounted hook in the component it says item is not defined.
You have to pass it via props. Props Documentation
pseudo example:
<my-component :info="someInfo" />
then in the component:
Vue.component('myComponent', {
// declare the props
props: ['info'],
template: '<span>{{ info }}</span>'
})

Vue js: Multiple options selection

Objective: To Select multiple options of a select tag.
Attempt: The documentation says: to implement a multi-select input, the property to be bound using v-model should be an array.
Errors: [Vue warn]: expects an Array value for its binding, but got String.
The value bound to (multipleSelections), is an array, so what is the reason for this?
Here is the jsfiddle.
script:
new Vue({
el:'#app',
data: function() {
return {
multipleSelections: ["Mr Potato (Manager)"],
data: null,
multiple: "true",
assets:["Mr Potato (Manager)", "Mr Blade (Manager)", "Mrs Spice (Manager)"]
}
},
created() {
console.log("selections: ",this.multipleSelections);
}
});
html:
<script src="https://unpkg.com/vue#2.0.6/dist/vue.js"></script>
<div class='container' id='app'>
<h2>{{"title".toUpperCase()}}</h2>
<p class='center help-text' v-if="multiple === 'true'">(Use ctrl or cmd to select multiple)</p>
<select
:multiple="multiple === 'true'"
v-bind:class="{ 'fix-height': multiple === 'true' }"
v-model="multipleSelections"
>
<option
v-for="asset in assets"
:value="asset">
{{asset}}
</option>
</select>
{{ multipleSelections }}
Just giving multiple="true" in select works. Here is jsfiddle link.
<select
multiple="true"
v-bind:class="{ 'fix-height': multiple === 'true' }"
v-model="multipleSelections"
>
I found this plug-in did the trick if your looking for something full featured. It also has great documentation (see links below).
https://vue-multiselect.js.org/
After you install the library check out the example straight from the documentation:
https://vue-multiselect.js.org/#sub-getting-started
<!-- Vue component -->
<template>
<div>
<multiselect v-model="value" :options="options"></multiselect>
</div>
</template>
<script>
import Multiselect from 'vue-multiselect'
// register globally
Vue.component('multiselect', Multiselect)
export default {
// OR register locally
components: { Multiselect },
data () {
return {
value: null,
options: ['list', 'of', 'options']
}
}
}
</script>
<!-- New step!
Add Multiselect CSS. Can be added as a static asset or inside a component. -->
<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
<style>
your styles
</style>

Categories

Resources