Dynamically select dropdown menu values based on HTML checkbox - vuejs2

I have a form with an HTML checkbox and two dropdown/select menus. If I check the checkbox, it should dynamically select values in the dropdown menus.
Unfortunately, I am having trouble getting this to work as it seems I have to manually select the values to make them appear.
If you check the box for "Top Rated", it should dynamically select Watermelon product and Black Diamond as the product subject.
Sandbox here: https://codesandbox.io/embed/restrict-values-on-toggle-mxiq3
Any tips and advice would be greatly appreciated
PostForm.vue
<template>
<div>
<form>
<input type="checkbox" v-model="form.topRated"> Top Rated
<br>
<br>
<label for="product_select_input">Product:</label>
<select v-if="form.topRated" id="product_select_input" v-model="form.product_id">
<option value="3">Watermelon</option>
</select>
<select v-if="form.topRated==false" id="product_select_input" v-model="form.product_id">
<option disabled value>Select</option>
<option
v-for="(product, index) in products"
:key="index"
:value="product.product_id"
>{{ product.product_name }}</option>
</select>
<br>
<br>
<label for="product_subject_input">Product Subject:</label>
<select v-if="form.topRated" id="product_subject_input" v-model="form.subject_id">
<option value="5">Black Diamond</option>
</select>
<select v-if="form.topRated==false" id="product_subject_input" v-model="form.subject_id">
<option disabled value>Select a Subject</option>
<option
v-for="(subject, index) in showRelatedSubj"
:key="index"
:value="subject"
>{{ subject.subject_name }}</option>
</select>
<br>
<br>
</form>
<pre>
<div>form: {{form}}</div>
<!-- <div>related subjects: {{showRelatedSubj}}</div> -->
</pre>
</div>
</template>
<script>
export default {
name: "PostForm",
data() {
return {
products: [
{
product_id: 1,
product_name: "Apple"
},
{
product_id: 2,
product_name: "Banana"
},
{
product_id: 3,
product_name: "Watermelon"
},
{
product_id: 4,
product_name: "Potato"
}
],
subjects: [
{
subject_id: 1,
product_id: 1,
subject_name: "Granny Smith"
},
{
subject_id: 2,
product_id: 1,
subject_name: "McIntosh"
},
{
subject_id: 3,
product_id: 2,
subject_name: "Cavendish"
},
{
subject_id: 4,
product_id: 3,
subject_name: "Jubilee"
},
{
subject_id: 5,
product_id: 3,
subject_name: "Black Diamond"
},
{
subject_id: 6,
product_id: 4,
subject_name: "Russet"
},
{
subject_id: 7,
product_id: 4,
subject_name: "Yukon Gold"
}
],
form: {
topRated: false,
product_id: "",
subject_id: ""
}
};
},
computed: {
showRelatedSubj() {
return this.subjects.filter(
subject => this.form.product_id === subject.product_id
);
}
}
};
</script>

you could add a change event listener to your input checkbox and set a method for that event.
<input #change="select_top_rated()" type="checkbox" v-model="form.topRated">
select_top_rated() {
if (this.form.topRated){
this.form.product_id = 3
this.form.subject_id = 5
} else{
this.form.product_id = null
this.form.subject_id = null
}
}
for disabling the select options after checking Top Rated checkbox, try attribute binding. :disabled in this case.
<select :disabled="select_disabled" v-if="form.topRated" id="product_select_input" v-model="form.product_id">
<option value="3">Watermelon</option>
</select>
define select_disabled in your data, set it to false initially.
and add this to your select_top_rated() method.
this.select_disabled = true

Related

Datalist disapearing in a simple vue example

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

Angular 8 how to pass current object and its index in change event

<pre>
<select (change)="getSelecteItem()">
<option *ngFor="let item of sampleDropDown">
{{item.value}}
</option>
</select>
<pre>
public sampleDropDown =
[{ id: '1', value: 'Test0' }, { id: '2', value: 'Test1' }, { id: '1', value: 'Test2' }];
getSelecteItem() {
}
</code>
I am binding dropdown using Angular 8 with *ngFor..
1) I want to pass current selected option in change event
2) I want to pass current selected option index in change event
you can do that by accessing the special variable $event.
In your template (HTML file)
<select (change)="getSelecteItem($event)">
<option *ngFor="let item of sampleDropDown">
{{ item.value }}
</option>
</select>
In your component:
getSelecteItem(event) {
const value = event.target.value;
console.log(value); //// test0, test1, etc...
}
<select (change)="getSelecteItem($event)">
<option *ngFor="let item of sampleDropDown" value="{{item.id}}" >
{{item.value}}
</option>
</select>
public sampleDropDown =
[{ id: '1', value: 'Test0' }, { id: '2', value: 'Test1' }, { id: '1', value: 'Test2' }];
getSelecteItem(event) {
event.currentTarget.options.selectedIndex
event.currentTarget.options[event.currentTarget.options.selectedIndex].text
event.currentTarget.options[event.currentTarget.options.selectedIndex].value
}

"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>

VueJS: How to have first form select input determine what to show in second select input?

I have a form with two select inputs. What the user selects in the first select input (product_id) is going to determine what options to show in the second select input. Being sort of new to JavaScript, I am struggling with how to write the logic for this in my Vue app.
Let me explain...(also live demo here)
I have two data arrays:
Products:
[
{
product_id: 1,
product_name: 'Apple'
},
{
product_id: 2,
product_name: 'Banana'
},
{
product_id: 3,
product_name: 'Watermelon'
},
{
product_id: 4,
product_name: 'Potato'
}
]
Subjects:
[
{
product_id: 1,
subject_name: 'Granny Smith'
},
{
product_id: 1,
subject_name: 'McIntosh'
},
{
product_id: 2,
subject_name: 'Cavendish'
},
{
product_id: 3,
subject_name: 'Jubilee'
},
{
product_id: 3,
subject_name: 'Black Diamond'
},
{
product_id: 4,
subject_name: 'Russet'
},
{
product_id: 4,
subject_name: 'Yukon Gold'
}
]
Form template:
<label for="product_select_input">Product:</label>
<select
id="product_select_input"
v-model="form.product"
>
<option disabled value="">Select</option>
<option
v-for="(product, index) in products"
:key="index"
:value="product.product_id"
>{{ product.product_name }}</option
>
</select>
<label for="product_subject_input">Product Subject:</label>
<select
id="product_subject_input"
v-model="form.subject"
>
<option disabled value="">Select a Subject</option>
<option
v-for="(subject, index) in subjects"
:key="index"
:value="subject.subject_id"
>{{ subject.subject_name }}</option
>
</select>
I thought that I would add a computed property called showRelatedSubjs and bind it to #change on the initial product select, but that did not work and I get the following error in console: Cannot read property 'product_id' of undefined
computed: {
showRelatedSubj() {
if (this.form.product === this.subject.product_id) {
return this.subjects.filter(subject => subject.includes(this.subject_name))
} else {
return ''
}
}
}
Anyone have any tips or solutions ? Thank you.
My live demo is available here
A few issues:
The objects in subjects contain product_ids, yet your v-model is bound to subject.subject_id (nonexistent).
The name of your computed property suggests the intention is to return the related subjects based on the selected product. That should be done with only the filter() like this:
showRelatedSubj() {
return this.subjects.filter(
subject => this.form.product === subject.product_id
);
}
updated codesandbox

'[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>