vue.js populate 2 dropdowns from json data - javascript

In my third exercise, I have a json file that contains info about cars and their models.
I am trying to populate 2 dropdowns from that file:1 for cars and the corresponding models in the other dropdown but not able to do that.
In the models dropdown that I did below, i see some null elements! (maybe corresponding of a place occupied in previos selection).
I would like to have the models dropdown always have the first item by default.
Thanks for help.
json file data:
[
{"name": "Abarth",
"models": [
{"name": "124 Spider", "series": null},
{"name": "500", "series": null},
]
},
{"name": "Acura",
"models": [
{"name": "MDX", "series": null},
{"name": "NSX", "series": null},
{"name": "RL", "series": null},
{"name": "RSX", "series": null},
]
},
]
My Code:
<template>
<div>
Make:<select #change="switchView($event, $event.target.selectedIndex)">
<option
v-for="(item, index) in logitems"
:key="index"
v-bind:value="this.selected"
>
{{ item.name }}
</option>
</select>
Model:<select>
<option
v-for="(item, index1) in logitems"
:key="item"
>
{{ logitems[selectedIndex].models[index1]}} //not able to get the name !
</option>
</select>
</div>
</template>
<script>
import logs from "../assets/car-makes.json";
export default {
data() {
return {
logitems: logs,
selectedIndex: "0",
selected: {
name: "Abarth",
models: [
{
name: "124 Spider",
series: null,
},
{
name: "500",
series: null,
},
],
},
};
},
methods: {
switchView: function (event, selectedIndex) {
console.log(event, selectedIndex);
this.selectedIndex = selectedIndex;
},
},
};
</script>

Try like following snippet:
new Vue({
el: '#demo',
data() {
return {
logitems: [
{ name: "Abarth",
models: [{name: "124 Spider", series: null}, {name: "500", series: null},]
},
{ name: "Acura",
models: [{name: "MDX", series: null}, {name: "NSX", series: null},
{name: "RL", series: null }, {name: "RSX", series: null },]
},
],
selected: {
name: 'Abarth',
model: ''
}
};
},
computed: {
models(){
return this.logitems.filter(l => l.name === this.selected.name)
}
},
methods: {
clearModel() {
this.selected.model = this.logitems.find(l => l.name === this.selected.name).models[0].name
}
}
})
Vue.config.productionTip = false
Vue.config.devtools = false
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div>
Make:<select v-model="selected.name" #change="clearModel">
<option
v-for="(item, index) in logitems"
:key="index"
:value="item.name"
>
{{ item.name }}
</option>
</select>
Model:<select v-model="selected.model">
<option
v-for="(item, i) in models[0].models" :key="i">
{{ item.name }}
</option>
</select>
<p>{{ selected }}</p>
</div>
</div>

Related

How do I get values from multiple vue select instances?

I have 2 arrays of objects like below. I need to create a select for every questions element, and I need to have the options connected with the selections by the id. In this case I need to have 2 selects, the first one will have 1000, 5000 and 10000 as options meanwhile the second select will have yes and no as options
const questions = [{
'id': 1,
'question': 'KM'
},
{
'id': 2,
'question': 'Works'
}
]
const selections = [{
'question_id': 1,
'value': 1000
},
{
'question_id': 1,
'value': 5000
},
{
'question_id': 1,
'value': 10000
},
{
'question_id': 2,
'value': 'yes'
},
{
'question_id': 2,
'value': 'no'
}
]
I made it like this in vue but the issue is that I can't save the data in the v-model as I'm returning the values from cars() and not a variable specified in data()
<div class="form-group" v-for="item in questions" v-bind:key="item.question">
<h5 v-if="showQuestion(item.id)">{{ item.question }}</h5>
<div class="tour-options-select" v-if="showQuestion(item.id)">
<select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown" v-model="questions.value">
<option v-for="item1 in cars(item.id)" v-bind:key="item1.id" :value="item1.display_name">{{ item1.display_name }}</option>
</select>
</div>
</div>
Ultimately, I just need to know, how do I get the value when I have a structure like the one I defined above?
If you have an array in data() to store your selected options, you can use v-model to dynamically bind with an element in that array if you give it an index:
new Vue({
el: '#app',
data: {
questions: [{
'id': 1,
'question': 'KM'
},
{
'id': 2,
'question': 'Works'
}
],
selections: [{
'question_id': 1,
'value': 1000
},
{
'question_id': 1,
'value': 5000
},
{
'question_id': 1,
'value': 10000
},
{
'question_id': 2,
'value': 'yes'
},
{
'question_id': 2,
'value': 'no'
}
],
selected: [],
},
methods: {
cars: function(id) {
return this.selections.reduce((arr, currSel) => {
if (currSel.question_id == id)
arr.push(currSel);
return arr;
}, []);
},
}
});
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<div id="app">
<div v-for="(question, index) in questions" :name="question.question" :key="question.id">
<select v-model="selected[index]">
<option v-for="option in cars(question.id)" :key="option.question_id" :value="option.value">
{{ option.value }}
</option>
</select>
</div>
<p>Selected:</p>
<pre>{{ $data.selected }}</pre>
</div>
Another approach would be to use events to handle the changes, calling a custom function each time the user makes a selection, eg using #change:
new Vue({
el: '#app',
data: {
questions: [{
'id': 1,
'question': 'KM'
},
{
'id': 2,
'question': 'Works'
}
],
selections: [{
'question_id': 1,
'value': 1000
},
{
'question_id': 1,
'value': 5000
},
{
'question_id': 1,
'value': 10000
},
{
'question_id': 2,
'value': 'yes'
},
{
'question_id': 2,
'value': 'no'
}
],
},
methods: {
cars: function(id) {
return this.selections.reduce((arr, currSel) => {
if (currSel.question_id == id)
arr.push(currSel);
return arr;
}, []);
},
}
});
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<div id="app">
<div v-for="(question, index) in questions" :name="question.question" :key="question.id">
<select #change="console.log('Option', $event.target.value, 'chosen for Q', question.id)">
<option selected disabled>Select...</option>
<option v-for="option in cars(question.id)" :key="option.question_id" :value="option.value">
{{ option.value }}
</option>
</select>
</div>
</div>
This way will give you more freedom to store or process the data as you wish, but you'll have to do it manually.

Using v-for with nested object in Vue

I have data in this form:
itemlist : {
"dates": [
"2019-03-15",
"2019-04-01",
"2019-05-15"
],
"id": [
"arn21",
"3sa4a",
"wqa99"
],
"price": [
22,
10,
31
]
}
I want to use v-for in my created component that loops through this object treating every index in those 3 nested arrays as one observation. So dates[0], id[0] and price[0]correspond to same item, dates[1] id[1] price[1] is second and so on.
So In other words I think I need to transform this into, but not sure:
0 : {
dates: "2019-03-15",
id: "arn21",
price: 22,}
1:{
dates: "2019-04-01",
id: "3sa4a",
price: 10}
}
2:...
Thats how I pass the data to the component:
<tempc v-for="i in itemlist" :key="i.id" :price="i.price" :dates="i.dates"></temp>
But this does not work for the original data
You can create a computed property for this:
Vue.component('my-component', {
template: '#my-component',
data() {
return {
itemlist: {
"dates": [
"2019-03-15",
"2019-04-01",
"2019-05-15"
],
"id": [
"arn21",
"3sa4a",
"wqa99"
],
"price": [
22,
10,
31
]
}
};
},
computed: {
// Note: here I assume these arrays will always have the same length
mergedList() {
return this.itemlist.dates.map((dates, i) => {
return {
dates,
id: this.itemlist.id[i],
price: this.itemlist.price[i]
};
});
}
}
});
var vm = new Vue({
el: '#app'
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.21/vue.min.js"></script>
<div id="app">
<my-component></my-component>
</div>
<template id="my-component">
<ul>
<li v-for="i in mergedList" :key="i.id" :price="i.price" :dates="i.dates">
{{i.id}} - ${{i.price}} ({{i.dates}})
</li>
</ul>
</template>

Vue Tables 2 with Slots. How to pass data id to event handler?

I'm using a slot to display a button in Vue Tables 2. How can I pass the id of the warehouse i.e. 123 or 456 to the edit() event handler?
I've tried adding props (as this is what the docs show). But I haven't had any luck. I'm using Vue Tables 2 in a component.
<template>
<div>
<h1>How to pass warehouse id to edit() method?</h1>
<v-client-table :columns="columns" :data="warehouses" :options="options">
<span slot="actions" slot-scope="{ WarehousesMin }">
<button v-on:click="edit">Edit</button>
</span>
</v-client-table>
</div>
export default {
name: 'WarehousesMin',
data() {
return {
warehouses: [
{"id": 123, "name": "El Dorado", "loc": "EDO"},
{"id": 456, "name": "Tartarus", "loc": "TAR"}
],
options: {
headings: {name: 'Name', code: 'Loc', actions: 'Actions'}
},
columns: ['name', 'loc', 'actions'],
}
},
methods: {
edit (warehouseId) {
// How to get id of warehouse here? i.e. 123 or 456
}
}
}
I haven't used this library before, but as far as I know about Vue slots, you can change your code into this and try again:
<template>
<div>
<h1>How to pass warehouse id to edit() method?</h1>
<v-client-table :columns="columns" :data="warehouses" :options="options">
<span slot="actions" slot-scope="{row}">
<button v-on:click="edit(row.id)">Edit</button>
</span>
</v-client-table>
</div>
and in script part, change to:
export default {
name: 'WarehousesMin',
data() {
return {
warehouses: [
{"id": 123, "name": "El Dorado", "loc": "EDO"},
{"id": 456, "name": "Tartarus", "loc": "TAR"}
],
options: {
headings: {name: 'Name', code: 'Loc', actions: 'Actions'}
},
columns: ['id', 'name', 'loc', 'actions'],
}
},
methods: {
edit (warehouseId) {
// The id can be fetched from the slot-scope row object when id is in columns
}
}
}
I think this ought to work, but if not please let me know.

Vue v-for after condition using vuex

While I am trying to create a form I encountered this problem which I don't have any solution.
There is a Vuex data on Vehicles Make and Model of vehicle, now once the make is selected, I want the other form to loop through the selected Make and find other models... something like that.
Here is what I did so far:
cars.js - (vuex module)
const state = {
make: [
{
name: 'Audi',
carid: '1',
models: [
{
modelid: '1.1',
name: 'A7',
},
{
modelid: '1.2',
name: 'A8',
},
],
},
{
name: 'BMW',
carid: '2',
models: [
{
modelid: '2.1',
name: '5 Series',
},
{
modelid: '2.2',
name: '7 Series',
},
],
},
],
}
Cars.vue
<template>
<div class="labelos">
<div class="label-name">
<h4>Car make:</h4>
</div>
<div class="label-body">
<label for="car-make">
<select v-model="selectedType" name="carmake" required>
<option value=""></option>
<option v-for="(cars, index) in cars.make" :key="index" :value="cars.carid">{{ cars.name }}</option>
</select>
</label>
</div>
</div>
<div class="labelos">
<div class="label-name">
<h4>Car model:</h4>
</div>
<div class="label-body">
<label for="car-model">
<select>
<option value=""></option>
<option v-for="(model, index) in cars.make" :key="index" :value="cars.carid">{{ model.carid }}</option>
</select>
</label>
Model:
</div>
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'cars',
data() {
return {
selectedType: '',
selectedCity: '',
};
},
methods: {
},
components: {
Headers,
Footers,
},
computed: {
...mapState([
'cities', 'cars',
]),
},
};
</script>
So as you can see on first label I am looping through makes, and once a car make is selected that carid is saved on selectedType, now how is that possible to load second dropdown according to that selection, so if carid 1 is selected, the list will load car models available on given carid (in this example carid 1)
Looking forward to hear from someone, I am stuck here.. I don't know any solution how to do this... this is so far I have done
Cheers
You should create a computed property which returns model options based on the value of the selected make type. Then you can bind to that and it will automatically update whenever the selected make changes:
models() {
if (this.selectedType) {
return this.cars.make.find((car) => car.carid === this.selectedType).models;
}
}
Here's a working example:
const store = new Vuex.Store({
state: {
cars: {
make: [{
name: 'Audi',
carid: '1',
models: [
{ modelid: '1.1', name: 'A7' },
{ modelid: '1.2', name: 'A8' },
]
}, {
name: 'BMW',
carid: '2',
models: [
{ modelid: '2.1', name: '5 Series' },
{ modelid: '2.2', name: '7 Series' }
],
}]
}
}
})
new Vue({
el: '#app',
store,
data() {
return {
selectedType: '',
};
},
computed: {
...Vuex.mapState(['cars']),
models() {
if (this.selectedType) {
return this.cars.make.find((car) => car.carid === this.selectedType).models;
}
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.min.js"></script>
<div id="app">
<h4>Car make:</h4>
<select v-model="selectedType" name="carmake" required>
<option value=""></option>
<option v-for="(cars, index) in cars.make" :key="index" :value="cars.carid">{{ cars.name }}</option>
</select>
<h4>Car model:</h4>
<select>
<option value=""></option>
<option v-for="(model, index) in models" :key="index" :value="model.modelid">{{ model.name }}</option>
</select>
</div>
Working example with your data:
const state = {
make: [
{
name: 'Audi',
carid: '1',
models: [
{modelid: '1.1', name: 'A7'},
{modelid: '1.2', name: 'A8'}
]
}, {
name: 'BMW',
carid: '2',
models: [
{modelid: '2.1', name: '5 Series'},
{modelid: '2.2', name: '7 Series'}
]
}
]
}
new Vue({
el: '#app',
data: {
state: state,
selected: 0
},
computed: {
models () {
var maker = this.state.make.find(m => m.carid === this.selected)
return maker ? maker.models : []
}
}
})
<div id="app">
<select v-model="selected">
<option value="0" selected>Choose maker</option>
<option
v-for="maker in state.make"
:key="maker.carid"
:value="maker.carid"
>{{ maker.name }}</option>
</select>
<br>
<select>
<option value="0" selected>Select model</option>
<option
v-for="model in models"
:key="model.modelid"
:value="model.modelid"
>{{ model.name }}</option>
</select>
</div>
<script src="https://unpkg.com/vue#2.5.3/dist/vue.min.js"></script>
If you can, change 'modelid' to simple integers - 1, 2, etc., at least. And if you can and you know how to do it, change your data structure - divide makers and models to separate arrays/objects.
Here's a plugin for this specific task you're trying to accomplish: vue-dependon.
It hasn't been updated for 1-2years, but I think that you can check its source code and see how it works.
UPDATE:
All you need from the sourcecode is the loadOptions function and the code between L83 and L105.
You can adapt that code to your needs.

Angular ng-repeat filter on nested array in object

I'm trying to applay a filter in my ng-repeat based on a nested array. The object that is used for the ng-repeat:
Updated
master_array:
{
"0": {
"Employee_Id": "hni",
"comptencies": [
{
"Title": "Bunker Knowledge",
"Level": 1
},
{
"Title": "Bunker Knowledge",
"Level": 3
},
{
"Title": "IT Compliance",
"Level": 2
},
{
"Title": "Bunker Knowledge",
"Level": 5
}
],
}
}
JS:
$scope.myFilter = {
competencyTitle : ""
}
HTML:
<label>Competencies
<select ng-model="myFilter.competencyTitle" ng-options="item.Title for item in competencies_list"></select>
</label>
<tr ng-repeat="item in master_array | filter: { competencies: [{ Competency.Title: myFilter.competencyTitle }] }">
The above doesn't work.
Case
I have a list of employees and each employee has an id and array of competencies attached. Each item in this array has a comptency array attached, which holds the title an id of the competency. What I want is to be able to filter out employees with specific competencies.
Any suggestions?
I found a solution. You probably have to adapt it to your specific code:
The main idea is this: filter: { $: {Title: myFilter.competencyTitle.Title} }
The $ selects any element whose child is Title.
html
<label>Competencies {{myFilter.competencyTitle.Title}}
<select ng-model="myFilter.competencyTitle" ng-options="item.Title for item in competencies_list"></select>
</label>
<p ng-repeat="item in master_array | filter: { $: {Title: myFilter.competencyTitle.Title} }">{{item.employee_id}} {{item.competencies}} </p>
js - this is the model is used, I'm not sure if this reflects your actual model.
$scope.competencies_list = [{Title : "Math"},{Title : "English"},{Title : "Spanish"}];
$scope.master_array =
[
{
employee_id: "hni",
competencies:
[
{Title : "Math", "Level": 1},
{Title : "English", "Level": 2}
]
},
{
employee_id: "xyz",
competencies:
[
{Title : "Spanish", "Level": 3},
{Title : "English", "Level": 5}
]
}
];
$scope.myFilter = {
competencyTitle : ""
};

Categories