Generating select options with v-for using an object - vue.js

I have an object that contains user names in this structure:
clients: {
1: {
first_name:"John"
last_name:"Doe"
middle_name:"A"
},
2: {
first_name:"Jenny"
last_name:"Doe"
},
}
I want to loop though them in a select input as options
<option v-for="(value, client, index) in clients" :value="">{{ value }}</option>
I came until here, but I couldn't figure out how to organize the string properly. Maybe, is there a way to parse it in computed properties so I can have room to put code?
If I could use something like this, I think it would work, but couldn't figure out how to do it like this either.
computed:{
clientNameOptions() {
for (const key of Object.keys(this.clients)) {
return `<option value="` + this.clients[key].first_name + ' ' + this.clients[key].middle_name + ' ' +
this.clients[key].last_name + `"></option>`
}
}
}
What is the proper way of achieving it?

This is primarily a guess at what you want, but you could build your options using a computed property.
console.clear()
new Vue({
el:"#app",
data:{
clients: {
1: {
first_name:"John",
last_name:"Doe",
middle_name:"A"
},
2: {
first_name:"Jenny",
last_name:"Doe"
},
},
selectedClient: null
},
computed:{
options(){
return Object.keys(this.clients).map(k => {
let o = this.clients[k]
return `${o.first_name} ${o.middle_name ? o.middle_name : ''} ${o.last_name}`
})
}
}
})
<script src="https://unpkg.com/vue#2.2.6/dist/vue.js"></script>
<div id="app">
<select v-model="selectedClient">
<option v-for="option in options" :value="option">{{option}}</option>
</select>
<hr>
Selected: {{selectedClient}}
</div>

Related

How can I get a specifc selection in select vue.js?

How are you?
I'm studying Vue and I'm stuck on the current task not knowing where to go.
I have a select that when I click I need to show on screen only what corresponds to that selection. For example, when placing the "to do" option in the select, only the tasks with a concluded=false should appear on the screen. I've only gotten this far and I need help to continue. Can you help me? Thanks
This is my App.vue
<template>
<div id="app">
<h1>Lista de Tarefas</h1>
<List :data="list" #remove="handleRemove"/>
<Form #add="addNewTask" #onChange="handleN"/>
</div>
</template>
<script>
import List from "./components/List.vue";
import Form from "./components/Form.vue";
export default {
components: {
List,
Form,
},
data() {
return {
list: [],
};
},
methods: {
addNewTask(newTask) {
this.list.push(newTask);
},
handleRemove(item) {
const index = this.list.findIndex(i => i.id === item.id)
this.list[index].excluded = true
},
handleN(item) {
const index = this.list.findIndex(i => i.id === item.id)
this.list[index].concluded = true
}
},
};
</script>
This is my List.vue
<template>
<ul>
<select v-model="selected" #change="onChange($event)">
<option disabled value="">Escolha a visualização</option>
<option v-for="option in options" :key="option.text">
{{ option.text }}
</option>
</select>
<li v-for="item in itens" :key="item.id">
<input type="checkbox" id="checkbox" v-model="item.concluded" />
<label for="checkbox"> {{ item.description }} </label>
<button #click="() => $emit('remove', item)">Excluir</button>
</li>
</ul>
</template>
<script>
export default {
props: {
data: {
type: Array,
default: () => {},
},
},
data() {
return {
selected: "",
options: [
{ text: "Todos", value: "1" },
{ text: "A fazer", value: "2" },
{ text: "Concluído", value: "3" },
{ text: "Deletado", value: "4" },
],
};
},
computed: {
itens() {
return this.data.filter((item) => item.excluded === false);
},
},
methods: {
onChange(event) {
console.log(event.target.value);
return this.data.filter((item) => item.concluded === false);
},
},
};
</script>
This is my Form.vue
<template>
<form #submit.prevent="handleNewTask">
<input type="text" v-model="newTask" placeholder="Insira a tarefa"/>
<input type="submit" value="Adicionar"/>
</form>
</template>
<script>
import Task from '../types/Task.js'
export default {
data() {
return {
newTask: "",
};
},
methods: {
handleNewTask() {
this.$emit('add', new Task(this.newTask))
this.newTask = ''
}
},
};
</script>
And this is my Task.js
export default class {
constructor(description) {
this.description = description,
this.id = Math.random(),
this.concluded = false,
this.excluded = false
}
}
I watch some tutorials, read the documentation and some StackOverflow questions but I really can't get out of here
Thanks in advance for the help
Based on how you have structured your app, our only concern should be with the List.vue file.
Your goal is to filter the results based on the selection (selected property). However, your issue is that you are not even using that anywhere.
I know you are hard coding the filter on the onChange method but that is, first of all wrong because you aren't really changing anything (you are returning an array), and secondly it's inefficient.
A better way to do it is to update the computed itens function like so:
itens() {
return this.data.filter((item) => {
if (this.selected === '1'){
return item.concluded === false
} else if (this.selected === '2'){
// filter another way
} else if (... // so on and so forth
});
},
Also, I would filter out the excluded items before sending them to the component. If you aren't going to use it, don't send it.
Remove the onChange event on the <select> and the associated method since they are now unused.

Pre-select a VUE2 drop-down

I have a vue2 app which I need to pre-select a dropdown but for the life of me, I can't figure it out.
I have looked and tried everything in:
How to preselect current value in a select created with v-repeat in Vue.js
Normal HTML
<select ref="courierList" id="courierList" class="form-control" v-model="shippingDetails.selectedCourier" #change="selectedCourierDd">
<option :value="courier.name" v-for="(courier, i) in couriers" :key="i">
{{ courier.name }}
</option>
</select>
data() {
return {
couriers: [],
.... OTHER DATA ITEMS
}
},
beforeMount() {
this.fetchCouriers();
},
fetchCouriers() {
axios.get('/couriers')
.then((response) => {
this.couriers = response.data.couriers;
.... OTHER CODE
Tried code > 1
Adding the below to the option
selected="{{ courier.name === preselectedCourierName ? 'true' : 'false' }}">
also tied without the true/false
Tried code > 2
Adding the below to the option
v-bind:selected="courier === preselectedCourierName"
and the below
data() {
return {
.... OTHER DATA ITEMS
preselectedCourier: [],
preselectedCourierName: ''
}
fetchCouriers() {
axios.get('/couriers')
.then((response) => {
this.couriers = response.data.couriers;
.... OTHER CODE
console.log('couriers', this.couriers[0])
this.preselectedCourier = this.couriers[0];
this.preselectedCourierName = this.preselectedCourier.name;
console.log('preselectedCourier', this.preselectedCourier)
console.log('preselectedCourierName', this.preselectedCourierName)
gives
Tried code > 3
<option :value="courier.name" v-for="(courier, i) in couriers" :key="i" :selected="courier.name === 'APC'">
no errors but dropdown still not pre-selected
The fix is in the mounted hook set the v-model of the select
<select v-model="shippingDetails.selectedCourier">
mounted() {
this.shippingDetails.selectedCourier = 'APC';
}
Give me exactly what i wanted

select value unset after click button

select with options are generated dynamically.
When button 'GO' were click select options generates again with different data. But the issue is when user select option 1 and click 'go' automatically option 1 is selected from next select, how to clear that?
my code:
<select v-model="key" #change="onChange($event)">
<option v-for="(option, index) in passSelect" :value="index" v-if="option!==null" :data-foo="option" #click="onChange($event)" #click="onClick($value)">
{{ option }}
</option>
</select>
<button #click="onChildClick" class="button">Go -></button>
methods:
onChildClick() {
this.counter++;
this.loadAgain();
},
getSelect(){
this.passSelect = this.checkExist();
},
onChange(event) {
this.selectedIndex = event.target.value;
this.selectedValue = event.target.options[event.target.value].dataset.foo;
},
loadAgain(){
this.getSelect();
},
Selection is determined by the v-model, which is using the property key. As you're using the index for the value this will cause the option with the same index as the previous list to be selected.
You need to clear the value of key to reset the <select>:
new Vue({
el: '#app',
data () {
return {
counter: 0,
key: null,
passSelect: [],
selectedIndex: null,
selectedValue: null
}
},
created () {
this.getSelect();
},
methods: {
onChildClick () {
this.counter++;
this.loadAgain();
},
getSelect () {
this.key = null;
this.selectedIndex = null;
this.selectedValue = null;
this.passSelect = getOptionsList();
},
onChange (event) {
const value = event.target.value;
if (value) {
this.selectedIndex = event.target.value;
this.selectedValue = event.target.options[event.target.value].dataset.foo;
}
},
loadAgain () {
this.getSelect();
}
}
})
function getOptionsList () {
return ['Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'].filter(c => {
return Math.random() > 0.4;
});
}
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<div id="app">
<select v-model="key" #change="onChange($event)">
<option v-for="(option, index) in passSelect" :value="index" v-if="option !== null" :data-foo="option">
{{ option }}
</option>
</select>
<button #click="onChildClick" class="button">Go -></button>
<p>counter: {{ JSON.stringify(counter) }}</p>
<p>key: {{ JSON.stringify(key) }}</p>
<p>selectedIndex: {{ JSON.stringify(selectedIndex) }}</p>
<p>selectedValue: {{ JSON.stringify(selectedValue) }}</p>
</div>
I've also cleared selectedIndex and selectedValue to try to keep the data consistent.
Some other notes:
I've got rid of the 2 click listeners on the <option>. Not really sure what they were for but you shouldn't have had 2 listeners for the same event on the same element.
key and selectedIndex are almost the same thing. The only difference is that selectedIndex ends up being a string whereas key is a number. Not clear why you aren't just using selectedIndex for your v-model directly.
I don't know what checkExist does but passSelect feels like it should be a computed property from the code provided.
There shouldn't be any need to use data-foo to pass the option to the listener. You can get the relevant option directly from the data once you have the index. All of which assumes you actually need the index, otherwise you could just bind the value directly to the string option.

Multiple select on the edit form

I have the following form:
This is the edit form.
As you can see I have a multiple select. I need to bind the values from the server to the select.
Here is structure of my objects from the server.
1) All elements for the multiple select:
2) Particular objects, that I want to see selected. As you can see, there's an additional field called 'pivot'.
As a result, I would like to see the following when I open my form:
I have tried something like this, but without success:
<div class="form-group">
<label for="bk">Связанные бк</label>
<select class="form-control form-control-sm" id="bk" v-model="formFields.applicationBk" multiple>
<option v-for="bk in allBk" v-if="applicationBk.find(x => x.id === bk.id) 'selected'" >
{{ bk.name }}
</option>
</select>
Here is full js code:
<script>
import { EventBus } from '../../app';
export default {
name: "ApplicationEdit",
props: ['applicationId', 'name', 'offer', 'bundleId', 'isBlackMode', 'applicationBk', 'allBk'],
mounted: function(){
console.log(this.applicationBk)
},
methods:{
submit: function (e) {
window.axios.post('/application/edit/' + this.applicationId, this.formFields)
.then(res => {
console.log('Сохранил!');
$('#applicationEdit' + this.applicationId).modal('hide');
EventBus.$emit('reloadApplicationsTable');
}).catch(err => {
if(err.response.status === 422){
this.errors = err.response.data.errors || [];
}
//console.error('Ошибка сохранения приложения. Описание: ');
console.error(err)
});
}
},
data(){
return {
formFields: {
applicationId: this.applicationId,
applicationBk: this.applicationBk,
name: this.name,
offer: this.offer,
bundle_id: this.bundleId,
giraffe: this.isBlackMode,
bk: this.applicationBk,
},
errors: []
}
}
}
You might consider using your loop as you have but using v-model to an array of the selected values. Here is vue's example of this: https://v2.vuejs.org/v2/guide/forms.html#Select

Vue selectize, getting json data from option?

I'm using vue2-selectize to display list of options fetched from axios call:
<template>
<selectize v-model="selected" :settings="settings">
<option v-for="option in options" :value="option.id">
({{ option.author }}) - {{ option.description }}
</option>
</selectize>
</template>
<script>
export default {
props: ['old-value'],
data() {
return {
selected: this.oldValue,
options: [],
settings: {
preload: true,
placeholder: "Search All Authors",
dropdownParent: 'body',
closeOnSelect: true,
render: {
option: function (data) {
console.log(data);
return '<div>' +
data.displayName +
'<div class="item-bio">' +
data.bio +
'</div>';
}
},
load: async (query, callback) => {
axios.get(route('api.showAllAuthors')).then(response => {
this.options = response.data;
callback();
})
}
},
}
},
}
</script>
The issue is that once you setup the <option> for the select you can only work with the two values it passes to the render function (text and value) and not the original object (whereas the actual <option> has access to this object).
The manual mentions the optional parameter of dataAttr available for <option> tags, but setting <option :data-data="option"> has no effect and I still can't access the original properties.
How can I access the original JSON attributes that the <option> is using in the render function?
var value = selectizeObject.getValue(),
optionJson = selectizeObject.options[value];
selectizeObject is object for given select / input. For example with jQuery:
var selectizeObject = $('#my-select')[0].selectize;