Datalist disapearing in a simple vue example - vue.js

Try to select from datalist while a data property is updated on a interval.
What is wrong in my code?
http://jsfiddle.net/startflorin/gr6b1h7j/18
Mounted intervals:
setInterval((ctx) => { ctx.notification = "111"; }, 500, this);
setInterval((ctx) => { ctx.notification = "222"; }, 500, this);
Data:
data: {
notification: null,
demoList:[
{
id: 1,
name: "option 1",
},
{
id: 2,
name: "option 2",
},
{
id: 3,
name: "option 3",
},
],
},
My HTML code:
<div>
{{ notification }}
</div>
<input list='demoList' v-on:change="selectSymbolList(target.value)">
<datalist id="demoList">
<option v-for="item in this.demoList" v-bind:value="item.name" v-bind:key="item.id">{{ item.name }}</option>
</datalist>

To cache the rendering of <input> and <datalist> (to isolate them from unrelated changes in the component's template), put them into a component:
Vue.component('demo-list', {
props: ['items'],
template: `<div>
<input list='demoList'>
<datalist id="demoList">
<option v-for="item in items" v-bind:value="item.name" v-bind:key="item.id">{{ item.name }}</option>
</datalist>
</div>`
})
Note this example requires the runtime compiler to compile the template string. Otherwise, render functions would be required instead of template.
Then use the component in your app's template:
<div id="app">
<div>{{ notification }}</div>
<demo-list :items="demoList"></demo-list>
</div>
demo

Related

Wrong parameter received in function call

Why do I receive subject (object that I want) on first item but MouseEvent from all other subject changes?
<template v-for="subject in subjects">
<select v-model="subject.name" class="form-control" #change="setNote(subject)">
<option v-for="vsub in validSubjects" :value="vsub.id_subject">{{ vsub.name }}</option>
</select>
</template>
This works for me:
var app = new Vue({
el: '#app',
data: {
message: 'Choose a subject: ',
subjects: [{
name: "Maths"
}, {
name: "Science"
}],
validSubjects: [{
id_subject: "1",
name: "Maths"
}, {
id_subject: "2",
name: "Science"
}, {
id_subject: "3",
name: "English"
}]
},
methods: {
setNote(subject) {
console.log(subject);
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
{{ message }}
<template v-for="subject in subjects">
<select v-model="subject.name" class="form-control" #change="setNote(subject)">
<option v-for="vsub in validSubjects" :value="vsub.id_subject">{{ vsub.name }}</option>
</select>
</template>
</div>

Using a filter inside a v-for?

Inside a v-for loop how can I apply a filter to the text? My inline template:
<select>
<option v-for="(item, index) in items" :key="index" :value="item.id" v-text="item.name | capitalize"></option>
</select>
I get multiple warnings Property or method "capitalize" is not defined on the instance but referenced during render. Even though the filter is defined.
So I presume its some sort of scope issue in the loop? How can this be solved?
As Vue Guide: Filters mentions, Filters are usable in mustache interpolations and v-bind expressions, not including the directives.
For your codes,
Solution 1 will be mustache interpolations.
Vue.filter('global-capitalize', function (value) {
return value.toUpperCase()
})
new Vue({
el: "#app",
data: {
items: [
{ text: "Learn JavaScript", id: 1 },
{ text: "Learn Vue", id: 2 },
{ text: "Play around in JSFiddle", id: 3 },
{ text: "Build something awesome", id: 4 }
]
},
filters: {
capitalize: function (name) {
return name.toUpperCase()
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<select>
<option v-for="(item, index) in items" :key="index" :value="item.id">
{{item.text | capitalize}}
</option>
</select>
<select>
<option v-for="(item, index) in items" :key="index" :value="item.id">
{{item.text | global-capitalize}}
</option>
</select>
</div>
Another solution is uses computed properties or methods.
new Vue({
el: "#app",
data: {
items: [
{ text: "Learn JavaScript", id: 1 },
{ text: "Learn Vue", id: 2 },
{ text: "Play around in JSFiddle", id: 3 },
{ text: "Build something awesome", id: 4 }
]
},
computed: {
computedItems: function () {
return this.items.map(item => {
return {text: item.text.toUpperCase(), id: item.id}
})
},
},
methods: {
filterFunc: function (name) {
return name.toUpperCase()
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select>
<option v-for="(item, index) in computedItems" :key="index" :value="item.id" v-text="item.text">
</option>
</select>
<select>
<option v-for="(item, index) in items" :key="index" :value="item.id" v-text="filterFunc(item.text)">
</option>
</select>
</div>

making select tag with vue-for

I am currently developing frontend with Argon for vue.js.
Free Argon template doesn't support type select for base-input so I decided to make it myself.
Here is my code:
<template>
// ...
<base-input alternative
type="select"
:options="genders"
addon-left-icon="ni ni-circle-08">
</base-input>
// ...
</template>
<script>
export default {
name: 'app-footer',
data() {
return {
genders: [
{ value: 0, text: 'Select Gender' },
{ value: 1, text: 'Male' },
{ value: 2, text: 'Female' }
]
}
}
}
</script>
BaseInput.vue:
<template>
// ...
<slot v-bind="slotData">
<select v-if="$attrs.type==='select'"
:value="value"
v-on="listeners"
v-bind="$attrs"
class="form-control"
:class="[{'is-valid': valid === true}, {'is-invalid': valid === false}, inputClasses]"
aria-describedby="addon-right addon-left">
<option v-for="(option, index) in $attrs.options"
:key="index"
v-bind:value="option.value">
{{$t(option.text)}}
</option>
</select>
<input
v-else
:value="value"
v-on="listeners"
v-bind="$attrs"
class="form-control"
:class="[{'is-valid': valid === true}, {'is-invalid': valid === false}, inputClasses]"
aria-describedby="addon-right addon-left">
</slot>
// ...
</template>
However, it only renders following html:
<select aria-describedby="addon-right addon-left" type="select" class="form-control"></select>
What is the problem here?
I found a solution. I used options for props. In vue.js options is a reserved keyword. I replaced it with optionlist and it works perfectly.

"prop" is undefined though it's being passed correctly

I've been following VueJS official documentation on passing data to child components with props; though I'm not working with a string template. I'm aware about what happens when your prop is camel case; you should write it as kebab case.
Nevertheless, this is not the case since it's all lowercase and won't work.
I'm using nuxt and I've separated my work into files, which are:
<template>
<div class="row">
<input type="text" name="" id="" placeholder="Write your question" v-model="text">
<select v-model="selectedField">
<option v-for="option in options" :key="option.id" :value="option.value">
{{ option.text }}
</option>
</select>
<button class="btn btn-sm btn-primary" #click="$emit('add-field')"
v-bind:class="{ disabled: ($parent.count <= 1 && $parent.count == identifier) }">
>{{identifier}}</button>
<button class="btn btn-sm btn-danger" #click="$emit('delete-field')">-</button>
</div>
Now for its JS file:
export default {
data () {
return {
options: [
{
id: 1,
value: 1,
text: "Radio"
},
{
id: 2,
value: 2,
text: "Rate"
},
{
id: 3,
value: 3,
text: "Text"
}
],
props: ['identifier'],
selectedField: 1,
text: "",
}
},
}
Now, for my parent component:
<template>
<div class="offset-md-3" id="qz">
<form-maker
v-for="item in questions" :key="item._id"
v-on:add-field="addField()"
v-on:delete-field="deleteField(item._id)"
v-bind:identifier="item._id" <<--What I want to set
ref="child"
></form-maker>
<button #click="saveForm" class="btn btn-large btn-success">SAVE</button>
</div>
</template>
Finally:
var vm = null;
export default {
layout: 'admin',
components: {
formMaker
},
data() {
return {
count: 1,
questions: [{
_id: 1//static
}]
}
},
}
What I'm trying to do is, to use the prop for some validations, nevertheless it throws the next error:
Property or method "identifier" is not defined on the instance but
referenced during render. Make sure that this property is reactive,
either in the data option, or for class-based components, by
initializing the property.
Thank you.
Here is where you go wrong. Props should not be in data(). See the code snippet below
<script>
export default {
props: ['identifier'],
data() {
return {
options: [
{
id: 1,
value: 1,
text: "Radio"
},
{
id: 2,
value: 2,
text: "Rate"
},
{
id: 3,
value: 3,
text: "Text"
}
],
selectedField: 1,
text: "",
}
}
}
</script>

'[Object object]' is displayed instead of label in Vue.js datalist

I'm using <datalist> drop-down menu to display group names in our project.
<data-list
ref="groupName"
name="groupName"
label="Groups: "
:options="groupList"
></data-list>
.....
methods:{
groupList(){
return this.$store.getters['Groups/getGroups']
}
}
But this is displayed in my UI:
I actually want the dropdown to display the label field, which is a group name, and I'll get the value of it. The structure of returned value looks like this:
[
{label: "test", value: 14},
{label: "Test1", value: 16},
{label: "Test2", value: 17},
{label: "Test3", value: 18},
]
It seems the bug is in your data-list component. Most likely you have something like this:
<!-- XXX: DON'T DO THIS -->
<option v-for="option in options" :value="option">{{option}}</option>
Vue.component('data-list', {
props: ['label', 'options'],
template: `
<div>
<label for="myinput">{{label}}</label>
<input id="myinput" list="mydata">
<datalist id="mydata">
<!-- XXX: DON'T DO THIS -->
<option v-for="option in options" :value="option">
{{option}}
</option>
</datalist>
</div>`,
});
new Vue({
el: '#app',
data() {
return {
groupList: [
{label: "test", value: 14},
{label: "Test1", value: 16},
{label: "Test2", value: 17},
{label: "Test3", value: 18},
]
};
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<data-list label="Groups: " :options="groupList"></data-list>
</div>
But you actually need to set the value of <option> to option.value and its inner text to {{option.label}} (matching your item's data structure):
<option v-for="option in options" :value="option.value">{{option.label}}</option>
Vue.component('data-list', {
props: ['label', 'options'],
template: `
<div>
<label for="myinput">{{label}}</label>
<input id="myinput" list="mydata">
<datalist id="mydata">
<option v-for="option in options" :value="option.value">
{{option.label}}
</option>
</datalist>
</div>`,
});
new Vue({
el: '#app',
data() {
return {
groupList: [
{label: "test", value: 14},
{label: "Test1", value: 16},
{label: "Test2", value: 17},
{label: "Test3", value: 18},
]
};
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<data-list label="Groups: " :options="groupList"></data-list>
</div>
you can to use like this in html and js.
actually following code is not a component.
sample HTML code
<datalist id="browsers">
<option v-for="lst in groupList" v-bind:value="lst">{{lst.label}}</option>
</datalist>
sample Vue.js code
data:{
groupObj: {},
groupList: []
},
methods:{
groupList(){
this.groupList = this.$store.getters['Groups/getGroups'];
},
},
mounted(){
this.groupList();
}
I understand the question as "How to work with objects in datalists in vue.js"
what are datalists?
datalists provides just templates to fill other controls.
mostly used with text input to provide combobox functionallity (allow also new content to be selected)
At this time implementation in browsers vary greatly, so better to just rely on basic label rendering (don't use value, since browsers handle it differently)
using it in vue with objects
Idea is to use strings and check on every input change if we have a perfect match. Using :value will show the id in chrome, which is probably not what you want. This doesn't work with same-named labels, but then again, such an input makes little sense in that case.
Vue.component('test-data-list', {
props: ['label', 'options', 'value'],
template: `
<div>
<label for="myinput">{{label}}</label>
<input id="myinput" list="data" #change="change" :value="getValue">
<datalist id="data">
<option v-for="option in options">
{{option.label}}
</option>
</datalist>
</div>`,
computed: {
getValue() {
return this.value ? this.value.label : '';
}
},
methods: {
change(e) {
let value = e.currentTarget.value;
if (value) {
let sel = this.options.filter(c => c.label == value);
if (sel.length == 1) {
this.selection = sel[0];
} else {
this.selection = {
label: value,
isNew: true
}
}
} else {
this.selection = undefined;
}
this.$emit('input', this.selection)
}
}
});
new Vue({
el: '#app',
data() {
return {
result: undefined,
groupList: [{
label: "something",
id: 1
},
{
label: "this too",
id: 2
},
{
label: "something different",
id: 3
}
]
};
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
Selected:
<span v-if="result">
"{{ result.label }}"
<span v-if="result.isNew">New!</span>
<span v-else> old object with id:{{result.id}}</span>
</span>
<span v-else>nothing</span>
</div>
<test-data-list label="Select" :options="groupList" v-model="result"></test-data-list>
</div>