How to get selected value from dropdown in vuejs? - javascript

HTML
<v-select
v-model="selectedBank"
:items="items"
item-text="bankName"
label="Select a bank"
persistent-hint
return-object
single-line
>
</v-select>
<v-btn
round
block
color="blue darken-3"
dark
large
#click="directToBank(items.bankName)"
>
CONTINUE
</v-btn>
JS
async directToBank(bankID) {
console.log("Came into directtobank", this.selectedBank.bankName)
}
How can I get the selected value of v-select upon clicking on the button ?
. .

If you are refering to vuetify you can continue reading.
Let's take this example (codepen):
new Vue({
el: '#app',
data: () => ({
items: [
{value: '1', bankName: 'Bank1'},
{value: '2', bankName: 'Bank2'},
],
selectedBank: null
}),
methods: {
directToBank() {
console.log("Label: ", this.selectedBank.bankName)
console.log("Value: ", this.selectedBank.value)
}
}
})
If you use other key for value in your items object you need to specify the item-value attribute in your v-select element, else it will use the "value" key by default.
More on v-select component

When you use return-object, you are bringing selectedBank into data() hence you will only need to call this.selectedBank.something inside your your #click function in the button.

Getting values from vuetify select is similar to getting the values for an even fired in javascript.
passing the even as a prop and the prop is the value you want
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
items: ['Foo', 'Bar', 'Fizz', 'Buzz'],
},
methods: {
select_value(e) {
console.log(e)
}
}
})
<v-select :items="items" label="Solo field" #change="select_value" solo></v-select>

Related

Why does vuejs replicates its v-model data when the v-model is referenced within a computed property?

In the following code:
JS
const App = {
template: '#app-template',
data: () => ({
selected: [],
items: Array.from({length: 50}, (x, i) => i+1).map(i => ({
id: i ,
name: `Item ${i}`,
subtitle: `Subtitle ${i}`
}))
}),
computed: {
parsedItems() {
this.selected;
return this.items.map(item => ({
someValue: 3,
...item
}));
}
}
}
new Vue({
vuetify: new Vuetify(),
render: h => h(App)
}).$mount('#app')
HTML
<script type="text/x-template" id="app-template">
<v-app>
{{selected}}
<v-container>
<v-virtual-scroll
:items="parsedItems"
:item-height="65"
height="500"
>
<template v-slot="{ item, index }">
<v-list-item-group
v-model="selected"
multiple
>
<v-list-item :key="item.id" :value="item">
<v-list-item-action>
<v-checkbox
:input-value="selected.includes(item.id)"
color="primary"
/>
</v-list-item-action>
<v-list-item-content>
<v-list-item-title>
Index: {{ index }} {{ item.name }}
</v-list-item-title>
<v-list-item-subtitle>
{{ item.subtitle }}
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</template>
</v-virtual-scroll>
</v-container>
</v-app>
</script>
<div id="app"></div>
When either of the checkboxes i checked or unchecked - the selected v-model always adds up another instance though it previously contains one already.
Removing this.selected; (line 16 in the Codepen below) fixes the issue.
I suspect that this.selected is somehow dereferences its own values and then can't validate the appearance of previously selected items.
Here's a Codepen with the issue at hand: https://codepen.io/MichaelKatz/pen/vYXXdgb
In my real-world scenario, I need to filter and manipulate items within the list, according to previously made selections (i.e remove / re-add items).
I do it by using a computed item property which derives its content from a previously selected items, from the selected v-model and my current solution will require me to JSON.stringify all of my objects, essentially making them value-based strings to keep things in check.
The v-model does not seem to work with Objects
<v-list-item :key="item.id" :value="item"> <!-- change this -->
<v-list-item :key="item.id" :value="item.id"> <!-- into this -->
And create a new computed property to "hydrate" those ids:
selectedItems() {
return this.selected.map(id => this.parsedItems.find(x => x.id === id))
}
Updated Codepen
It seems like accessing a v-model while filtering the items it refers to, creates a de-reference of the objects within it.
The best solution I could come up with was adding an additional computed property which will contain the logic involving this.selected.
It has indeed solved the issue for me.
computed: {
parsedItems() {
return this.items.map(item => ({
someValue: 3,
...item
}));
},
filteredItems() { // adding another computed property while using this.selected
this.selected;
return this.parsedItems;
}
}
}
From my perspective, the problem is you have used the multiple props, which will allow multiple selections.
<template v-slot="{ item, index }">
<v-list-item-group
v-model="selected"
multiple
>
Simply removing it will solve your problem.

Set default 'value' of custom Component v-model for v-text-field

Basically, I am using a custom component someone else wrote, and I want to set a default value for this v-text-field and i have tried EVERYTHING to override the editedItem.color v-model.
Nothing I am capable of coming up with will work!
I am a laravel php dev, and I could really use some help from my stack friends here.
I am at a new job, and i do not wish to fail.
<div v-if="formState === 'create'">
<v-text-field
v-model="editedItem.color"
:default="'#FF0000'"
:value="'#FF0000'"
:disabled="true"
label="Color*"
/>
</div>
As far as data, when i go the custom component, the data is as follows:
data: () => ({
formState: 'create',
loading: false,
items: [],
editedItem: {},
selectedItems: [],
}),
This seems like something that should be really easy. Just set a default value, and send that to the API. But with the v-model, it will not accept a v-bind:value or v-bind:default
This is a Vuetify component, and I am a newb Vue dev.
So in Summary, nothing will work without the v-model="editedItem.color", and yet, nothing will work if i do not set that default value.
The issue being that color picker returns an array, and we need it NOT to return an array.
So either I need to set the default value for 'create' mode to the #FF0000 hex value, or i need to parse out the returned value from the v-color-picker and JUST use the hex value and not return the array. So basically it all boils down to intercepting the editedItem.color for either solution.
This is my complete page/tags/index.vue page implementing the custom component.
Thanks SOF Fam!
<template>
<work-custom-table
v-model="headers"
:routes="routes"
:title="title"
settings-key="crud.table"
sort-by="name"
allow-merge
>
<template #item.preview="{ item }">
<v-chip :color="item.color">{{ item.name }}</v-chip>
</template>
<template #form="{editedItem, formState}">
<v-row>
<v-col>
<v-text-field
v-model="editedItem.name"
:disabled="formState === 'view'"
:rules="[$rules.required]"
label="Name*"
hint="*Required"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field
v-model="editedItem.description"
:disabled="formState === 'view'"
:rules="[$rules.required]"
label="Description"
/>
</v-col>
</v-row>
<v-row>
<v-col>
<div v-if="formState === 'create'">
<v-text-field
v-model="editedItem.color"
:disabled="true"
label="Color*"
/>
</div>
<div v-else>
<v-color-picker
id="tag-color"
v-model="editedItem.color"
:default="'#FF0000'"
:disabled="formState === 'view'"
class="elevation-0"
label="Color*"
hint="*Required"
mode="hexa"
hide-canvas
/>
</div>
</v-col>
</v-row>
</template>
</work-custom-table>
</template>
Any help would be great!
<v-text-field> is just a wrapper around an html <input>.
And in Vue, on <input>s, v-model and value are mutually exclusive. value is only read when you don't have two-way data binding (using v-model).
Which means all you need to do is provide the default value in the editedItem itself, before passing it to the <v-text-input> (and remove default & value). Example:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
formState: 'create',
editedItem: {
color: '#FF0000'
}
})
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#5.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<div v-if="formState === 'create'">
<v-text-field v-model="editedItem.color" :disabled="true" label="Color*" />
</div>
</div>
Obviously, if editedItem is coming from another component or from an external API, you'll have to intercept it and populate the default value of color on it if color does not have a truthy value. A generic example:
methods: {
getEditedItemFromApi() {
this.$http.get('some/api/url')
.then(r => this.editedItem = ({
...r.data,
// assumming the API returns the editingItem object
color: r.data.color || '#FF0000'
}));
}
}
(we're destructuring the response data and adding color property to all its existing properties, with a value of its own color property if it's anything truthy or the default value if it's falsey.
The gist of it is: you have to populate the default value on the actual property bound to v-model, prior to passing it to the <input>.
Here's the relevant part of Vue documentation on v-model.
And, to cover all cases, here's how you'd use a computed with set and get, allowing you map default values:
Vue.config.productionTip = false;
Vue.config.devtools = false;
new Vue({
el: '#app',
data: () => ({
items: [
{ id: 'one', color: 'black' },
{ id: 'two' }
],
selectedItem: null
}),
computed: {
editingItem: {
get() {
return { ...this.selectedItem, color: this.selectedItem?.color || '#FF0000' };
},
set(item) {
this.selectedItem = item;
}
}
}
})
.flexer {
display: flex;
align-items: center;
}
.flexer span {
width: 1em;
height: 1em;
border: 3px solid;
border-radius: 50%;
margin-left: .5rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<select v-model="selectedItem">
<option :value="null">Select item</option>
<option v-for="item in items" :value="item">{{item.id}}</option>
</select>
<div class="flexer" v-if="selectedItem">
<input v-model="editingItem.color" :disabled="true" />
<span :style="{ borderColor: editingItem.color }" />
</div>
<pre v-html="{ selectedItem, editingItem }" />
</div>
This would also cover the case when it's coming as prop, from a parent.
My solution has little to do with VUE, but hopefully it can help someone, I hit that a personal state where you start looking for other solutions.
The problem is that on 'create' the color-picker was returning an array, where on edit, it was returning the hex value, so my (maybe a little hacky) solution was to set a default value for the color value initially, and then set color on edit.
But instead of manipulating vue vars with getters and setters,
I went into my Laravel API FormRequest instance, and you can prepare your data before validation using prepareForValidation() method.
I did this:
protected function prepareForValidation(){
if(gettype($this->color) == 'array'){
$this->merge(['color' => $this->color['hex']]);
}
}
I was able to check for an array, and if array, parse out the value. Sadly, I was not able to get the get and set to work for me.
Thanks!

Execute method on enter key VueJS?

I am using vuetify and trying to create a method to add chips from the dropdown. Now i got most of the logic down but as you can see, the method multipleSelection does not fire off on the enter key but works fine onClick.
Here is a demo for the codepen.
So the method multipleSelection should fire off on the enter key.
new Vue({
el: '#app',
data() {
return {
arr: [],
items: [{
text: 'Foo',
value: 'foo'
},
{
text: 'Bar',
value: 'bar'
},
{
text: 'biz',
value: 'buzz'
},
{
text: 'buzz',
value: 'buzz'
}
],
}
},
methods: {
multipleSelection(item) {
this.arr.push(item)
console.log(this.arr)
},
deleteChip(item) {
console.log('delete')
this.arr = this.arr.filter(x => x !== item);
console.log(this.arr)
}
},
})
<link href="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#1.5.14/dist/vuetify.min.js"></script>
<div id="app">
<v-app id="inspire">
<v-container>
<v-combobox :items="items" label="Add Multiple Chips" multiple small-chips solo deletable-chips :value="arr">
<template v-slot:item="{ index, item }">
<v-list-tile-content #click.stop.prevent="multipleSelection(item)">
{{item.text}}
</v-list-tile-content>
</template>
<template v-slot:selection="{ index, item }">
<v-chip close dark color="info" #click:close="deleteChip(item)">
{{ item.text }}
</v-chip>
</template>
</v-combobox>
</v-container>
</v-app>
</div>
Any help will be appreciated. Thank you.
Since multipleSelection() is not being called from #keypress on v-slot:item, likely it's not where the event is being captured.
Taking a look at events on Vue Dev Tools, can see input $emit by <VCombobox> is the first one after pressing Enter.
So the following will get it, but this seems to mess with the position in the list for some reason I don't understand.
<v-combobox
...
#input.capture="(item) => multipleSelection(item)"
>
Better to add a listener,
mounted() {
this.$refs.combobox.$on('input', (items) => {
const item = items[items.length -1]; // getting all selected, so take the last
this.multipleSelection(item)
})
},
Note, I tested this on a local project with Vuetify v1.5.14.
Looks like you need #keyup
<v-list-tile-content
#keyup.enter.prevent="multipleSelection(item)" #click.stop.prevent="multipleSelection(item)">{{item.text}}
</v-list-tile-content>
Not sure about keypress....Vue docs show #keyup
https://v2.vuejs.org/v2/guide/events.html#Key-Modifiers

Event when "select-all" button clicked in Vuetify

I'm currently implementing a data table using Vuetify, but I have stumbled into a problem while trying to react to a click on the "select-all" button in a data table. Right now, when the select-all button is clicked, the currently visible rows are selected (which is exactly what I want). However, I would like to be notified of the user clicking on this select-all button.
My plan is to provide the user with a "select everything" button, once the user clicks this "select-all" checkbox, but I can't seem to find a way (without having to reside to hacks) to get notified of a click on the "select-all" button.
There is a toggle-select-all method.
<div id="app">
<v-app id="inspire">
<v-data-table
:value="selected"
#toggle-select-all="selectAll"
:items-per-page="itemsPerPage"
:headers="headers"
:items="desserts"
item-key="name"
show-select
class="elevation-1"
>
</v-data-table>
<v-dialog>
<v-card>
</v-card>
</v-dialog>
</v-app>
</div>
Javascript is below:
new Vue({
el: '#app',
vuetify: new Vuetify(),
methods: {
selectAll(event) {
if (event.status) {
alert('selected all')
} else {
alert('deselected all')
}
}
},
data () {
return {
selected: [],
itemsPerPage: 10,
headers: ['headers', 'data'],
desserts: ['your', 'data']
}
}
})
You can do this by using :value and #input on the Vuetify table rather than v-model. Check if the selected array is equal to items per page when the user selects something.
<div id="app">
<v-app id="inspire">
<v-data-table
:value="selected"
#input="enterSelect($event)"
:items-per-page="itemsPerPage"
:headers="headers"
:items="desserts"
item-key="name"
show-select
class="elevation-1"
>
</v-data-table>
<v-dialog>
<v-card>
</v-card>
</v-dialog>
</v-app>
</div>
Javascript is below:
new Vue({
el: '#app',
vuetify: new Vuetify(),
methods: {
enterSelect(values) {
if (values.length == this.itemsPerPage) {
alert('selected all')
}
}
},
data () {
return {
selected: [],
itemsPerPage: 10,
headers: ['headers', 'data'],
desserts: ['your', 'data']
}
}
})
Working example here: https://codepen.io/CodingDeer/pen/QWLyaog?editors=1010

VueJs Endless loop with computed variable using in v-select

I'm try to use a computed value in a v-select (from vuetify) and when I select a value in the select there is an endless loop.
I've reproduce my dirty code in this pen to illustrate my problem. Be careful this might block your navigator.
HTML code
<div id="app">
<v-app id="inspire">
<v-card color="grey lighten-4" flat>
<v-card-text>
<v-select
v-model="select"
label="Be careful when select a value :)"
chips
tags
:items="items">
</v-select>
</v-card-text>
</v-card>
</v-app>
</div>
JS Code
new Vue({
el: '#app',
data () {
return {
obj: {
values: [{'name':'Testing'}]
},
items: [
'Programming',
'Design',
'Vue',
'Vuetify'
]
}
},
computed: {
select: {
get: function () {
return this.obj.values.map(val => val.name).sort()
},
set: function (chipsValues) {
this.obj.values = chipsValues.map(val => {return {'name': val}})
}
}
}
})
What's the proper way to code this behavior ?
A quick fix would be to validate before setting the this.obj.values whether you are getting any new values. If the new value is larger/smaller than old value, you can set it, else ignore it.
Since Javascript is synchronous, you can get away with just checking the length of the arrays.
set: function (chipsValues) {
if( this.obj.values.length != chipsValues.length) {
this.obj.values = chipsValues.map(val => {return {'name': val}})
}
}
Here's the updated pen: https://codepen.io/anon/pen/XewjdJ?editors=1010

Categories