I use vuetify v-select.
I want to clone the v-select with the array options from the first v-select and disabled (or remove) the selected values in the other v-select.
It can be clone multiple time and I want that if for example the 4 v-select is selected option X so this X option will be disabled in all the other v-select (also in the first one and reverse).
for example the options array:
[
{ title: 'title 1', id: '1', status: '0' },
{ title: 'title 2', id: '2', status: '0' },
{ title: 'title 3', id: '3', status: '0' },
{ title: 'title 4', id: '4', status: '0' }
]
Example
You can have vuetify v-select to clone the values to multiple select boxes as well as remove the one which is already selected from rest of the select boxes
Here is the working codepen : https://codepen.io/chansv/pen/wvvzbLX?editors=1010
You can have any number of select boxes just by looping through and assign the index as key to select box
Find the code below
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-btn #click="addSelectBox(true)">add select box</v-btn>
<div v-for="id in Object.keys(selectItems)" :key="id">
<v-select
v-model="selectItems[id].selected"
:items="selectItems[id].available"
label="Standard"
item-key="id"
item-value="id"
multiple
chips
deletable-chips
clearable
#change="modifyOthers"
></v-select>
<v-btn #click="deleteSelectBox(id)">delete select box</btn>
</div>
</v-container>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
selectItems: {},
numberOfSelectBoxes: 4,
itemsBucket: [
{ title: 'title 1', id: '1', status: '0' },
{ title: 'title 2', id: '2', status: '0' },
{ title: 'title 3', id: '3', status: '0' },
{ title: 'title 4', id: '4', status: '0' }
],
allSelected: [],
allUnSelected: [],
}),
methods: {
modifyOthers(val, id) {
this.updateAllSelected();
this.updateAllUnselected();
this.updateAllAvailable();
},
updateAllSelected() {
this.allSelected = [];
var self = this;
Object.keys(self.selectItems).forEach(x => {
self.allSelected = self.allSelected.concat(self.selectItems[x].selected);
});
},
updateAllUnselected() {
this.allUnSelected = [];
var self = this;
this.allUnSelected = self.itemsBucket.map(x => x.id).filter(x => !self.allSelected.includes(x));
},
updateAllAvailable() {
var self = this;
Object.keys(self.selectItems).forEach(key => {
self.selectItems[key].available = self.itemsBucket.map(x => x.id).filter(x => {
return self.selectItems[key].selected.includes(x) || self.allUnSelected.includes(x);
});
});
},
addSelectBox(fromUI) {
var self = this;
if (fromUI) {
var currentLast = +Object.keys(self.selectItems)[Object.keys(self.selectItems).length -1];
var newIndex = currentLast + 1;
self.$set(self.selectItems, newIndex, {selected: '', available: []});
self.selectItems[newIndex].available = self.allUnSelected;
} else {
for (var i = 1; i <= this.numberOfSelectBoxes; i++) {
self.$set(self.selectItems, i, {selected: '', available: []});
self.selectItems[i].available = self.itemsBucket.map(y => y.id);
}
}
},
deleteSelectBox(id) {
delete this.selectItems[id];
this.modifyOthers();
}
},
created() {
this.addSelectBox(false);
this.updateAllUnselected();
}
})
Related
I'm a little new in Vue.js and currently I am having a problem with radios.
I have a form with different inputs. When I'm submiting the form I create a JSON file with all the form answers:
Instead of this output I want the value of the selected radio to be 'Checked'.
{
"pos_r_1":"Radio 1"
"pos_r_2":"",
"pos_r_3":"",
"pos_r_4":"",
"pos_t_5":"this a test",
}
LIKE THAT:
{
"pos_r_1":"Checked"
"pos_r_2":"",
"pos_r_3":"",
"pos_r_4":"",
"pos_t_5":"this a test",
}
How can I change the value of the radio to 'checked'?
HTML
<v-form class="text-left" name="form" id="form">
<v-radio-group
v-model="checked"
hide-details="auto"
row
>
<v-radio
v-for="radio in group"
:key="radio.id"
:id="radio.id"
:name="radio.id"
:label="radio.text"
:value="radio.text"
/>
</v-radio-group>
<v-text-field
id="pos_t_5"
name="pos_t_5"
label="Text"
v-model="textfield"
/>
<v-btn
class="p-2"
color="primary"
elevation="11"
#click="onSubmit"
>click me</v-btn>
</v-form>
Script
export default Vue.extend({
name: 'Test',
data: function () {
return {
checked: '',
textfield: '',
group: [
{id: 'pos_r_1', text: 'Radio 1'},
{id: 'pos_r_2', text: 'Radio 2'},
{id: 'pos_r_3', text: 'Radio 3'},
{id: 'pos_r_4', text: 'Radio 4'},
],
}
},
onSubmit() {
this.loading = true
const form = document.querySelector('form');
const data = new FormData(form);
let currentObj = this;
let url = '/report/form/store';
axios({
url,
method: 'post',
data,
}) .then(function (response) {
currentObj.output = response.data;
}) .catch( (error) => {
if (error.response && error.response.status === 422){
this.errors = error.response.data.errors;
}
});
}
}
})
I've tried to change the value of the Radios to 'checked' but that doesn't work because then when I click one radio all getting checked.
This is only an example of the form. The form will be big with more that 20 different questions.
Update
This is not the way to do it. I have to manipulate the value of the radios buttons inside a Form Model, where I will save all the form answers. Then I can change the value of the radio to 'checked' easier.
So, radio buttons works as it should to https://developer.mozilla.org/ru/docs/Web/HTML/Element/Input/radio.
If you need to send a request like pos_r_3: Radio 3, you have to do some transformation on it. I'd suggest the code like:
export default Vue.extend({
name: 'Test',
data: function () {
return {
checked: '',
group: [
{id: 'pos_r_1', text: 'Radio 1'},
{id: 'pos_r_2', text: 'Radio 2'},
{id: 'pos_r_3', text: 'Radio 3'},
{id: 'pos_r_4', text: 'Radio 4'},
],
}
},
onSubmit() {
this.loading = true
const form = document.querySelector('form');
const data = new FormData(form);
for (let i = 0; i < this.group.length; i++){
const currentGroup = this.group[i];
data.set(currentGroup.id, currentGroup.text === this.checked ? 'Checked' : '');
}
let currentObj = this;
let url = '/report/form/store';
axios({
url,
method: 'post',
data,
}) .then(function (response) {
currentObj.output = response.data;
}) .catch( (error) => {
if (error.response && error.response.status === 422){
this.errors = error.response.data.errors;
}
});
}
}
I got some problem with Vuetify treeview component. My goal is:
When I select some treeview's element and press expand /collapse button I want to see all children for this element, and then when I press the button once again I want to collapse all selected element.
Here's my code:
<template>
<v-container fluid>
<v-btn justify-center #click="expandCollapse"> Expand or collapse </v-btn>
<v-treeview
class="ml-4"
v-model="tree"
:open="items"
:items="items"
activatable
item-key="name"
>
<template slot="prepend" slot-scope="{ item }">
<v-list-tile-avatar
size="30"
style="min-width: 40px;"
tile
>
<img :src="imageType(item.type)" alt=""/>
</v-list-tile-avatar>
</template>
</v-treeview>
</v-container>
</template>
<script>
export default {
data: () => ({
items: [
{
name: 'Factory A',
type: 'board',
children: [
{
name: 'Line 1',
children: [{
name: 'Machine ABC',
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 2',
children: [{
name: 'Machine ABC 02',
children: [{
name: 'Part A',
type: 'part'
},
{
name: 'Part B',
type: 'part'
},
{
name: 'Part C',
type: 'part'
},
{
name: 'Part D',
type: 'part'
}
],
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 3',
children: [{
name: 'Machine ABC 03',
type: 'machine'
}],
type: 'board'
},
{
name: 'Line 4',
children: [{
name: 'Machine ABC 04',
type: 'machine'
}],
type: 'board'
}
]
}
]
}),
methods: {
imageType (type) {
switch (type) {
case 'board':
return require('#/assets/images/board.svg')
case 'machine':
return require('#/assets/images/machine.svg')
case 'part':
return require('#/assets/images/part.svg')
}
},
// ADDED
bfs: function (tree, key, collection) {
if (!tree[key] || tree[key].length === 0) return
for (var i = 0; i < tree[key].length; i++) {
var child = tree[key][i]
collection.push(child)
this.bfs(child, key, collection)
}
},
expandCollapse (item) {
const childs = []
const selectedIDs = []
childs.push(item)
this.bfs(item, 'children', childs)
}
}
}
</script>
Ok, I got the solution. I just added two if-statements to function.
if (this.open.indexOf(selectedIDs[0]) === -1) {
this.open = this.open.concat(childs.map(node => node.id))
} else {
this.open = this.open.filter((item) => !selectedIDs.includes(item))
}
Use the open and active event listeners to update the open/closed items.
To get the active items use the update:active event.
To get the open items use the update:open event.
on expandCollapse use the active items and the open items to determine whether to open or close, and then update the open to reflect the change. This part is just iterating through the items and running a comparing to active and open
Vuetify v-treeview how to get the get last selected element?
<v-treeview
v-model="treeModel"
:items="items"
selectable="selectable"
>
by treeModel I have all selected, but how can I get only the last item selected (clicked)?
by only providing the last item's id in the v-model
modified example from https://vuetifyjs.com/en/components/treeview#checkbox-color
option 1 - use v-on/#on update:active
** DOES NOT CURRENTLY WORK FOR VUETIFY v2 **
<div id="app">
<v-app id="inspire">
<v-treeview
v-model="selection"
selectable
selected-color="red"
:items="items"
#update:active="onUpdate"
></v-treeview>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
selection: [],
items: [
{
id: 1,
name: 'Applications :',
children: [
{ id: 2, name: 'Calendar : app' },
{ id: 3, name: 'Chrome : app' },
{ id: 4, name: 'Webstorm : app' },
],
},
{
id: 5,
name: 'Documents :',
children: [
{ id: 6, name: 'Calendar.doc' },
{ id: 7, name: 'Chrome.doc' },
{ id: 8, name: 'Webstorm.doc' },
],
},
],
}),
methods: {
onUpdate(selection) {
console.log(selection)
}
}
})
the problem is that if you're using vuetify v2.0.0 - v2.0.5 the action does not actually work for a selection but for activatable
## option 2 - use watch
this option, at the moment, is preferred. It uses a watch to trigger the action when the `v-model` changes
```html
<div id="app">
<v-app id="inspire">
<v-treeview
v-model="selection"
:items="items"
selectable
></v-treeview>
</v-app>
</div>
new Vue({
el: '#app',
vuetify: new Vuetify(),
watch:{
selection(newValue) {
this.onUpdate(newValue)
}
},
data: () => ({
selection: [],
items: [
{
id: 1,
name: 'Applications :',
children: [
{ id: 2, name: 'Calendar : app' },
{ id: 3, name: 'Chrome : app' },
{ id: 4, name: 'Webstorm : app' },
],
},
{
id: 5,
name: 'Documents :',
children: [
{ id: 6, name: 'Calendar.doc' },
{ id: 7, name: 'Chrome.doc' },
{ id: 8, name: 'Webstorm.doc' },
],
},
],
}),
methods: {
onUpdate(selection) {
console.log(selection)
}
}
})
If you want to find the last item that was selected, you can use an array diff here
watch:{
selection(newValue, oldVal) {
var arrDiff = myArrDiffDependency.added(newValue, oldValue)
this.onUpdate(arrDiff)
}
},
watch: {
selection() {
if (this.items.length > 1) {
this.items.shift();
}
},
},
Isto resolve
I have been searching for 3 level category listing sample. I found few samples for 2 levels. The below sample derived from 2 levels.
I was facing an issue with triggering v-model computed event after selecting subcategory item, to solve this we need to add v-model="subcategory" and the same has to be declared in data()
Click here
**HTML**
<link rel='stylesheet prefetch'
href='https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.2/css/bulma.min.css'>
<div class="container" id="app">
<div class="section">
<h1 class="title">Vue.js - Conditional Select</h1>
<hr>
<conditional-select
:categories="categories":newcategories="newcategories"
:subcategories="subcategories" ></conditional-select>
</div><!-- /.section -->
</div><!-- /.container -->
**Vue.js**
Vue.component('conditional-select', {
template: `
<div id="ConditionalSelect">
<div class="select">
<select v-model="category" name="category">
<option v-for="category in categories"
:value="category.id">{{ category.name }}</option>
</select>
</div>
<div class="select">
<select v-model="subcategory" name="subcategory">
<option v-for="subcategory in conditionalSubcategories"
:value="subcategory.subid" :selected="subcategory.selected == true">{{
subcategory.name }}</option>
</select>
</div>
<div class="select">
<select name="newcategory">
<option v-for="newcategory in conditionalNewcategories"
:value="newcategory.id" :selected="newcategory.selected == true">{{
newcategory.name }}</option>
</select>
</div>
</div>
`,
props: ['categories', 'subcategories', 'newcategories'],
data() {
return {
category: '',
subcategory: '',
}
},
computed: {
conditionalSubcategories() {
return this.subcategories.filter(subcategory => {
return subcategory.category_id == this.category;
});
},
conditionalNewcategories() {
return this.newcategories.filter(newcategory => {
return newcategory.subcategory_id == this.subcategory;
});
},
},
created() {
let category = this.categories.find(category => {
return category.selected == true;
});
let subcategory = this.subcategories.find(subcategory => {
return subcategory.selected == true;
});
this.category = category.id;
this.subcategory = subcategory.subid;
}
});
var app = new Vue({
el: '#app',
data: {
categories: [
{ id: '0', name: 'Select a category', selected: true },
{ id: '1', name: 'Games', selected: false },
{ id: '2', name: 'Apps', selected: false }
],
subcategories: [
{ subid: '0', category_id:'1', name: 'Select a subcategory',
selected:
false },
{ subid: '1', category_id:'1', name: 'Adventure', selected: false
},
{ subid: '2', category_id:'1', name: 'Shooter', selected: false },
{ subid: '3', category_id:'1', name: 'Simulation', selected: false
},
{ subid: '4', category_id:'1', name: 'Sports', selected: false },
{ subid: '5', category_id:'2', name: 'Illustration', selected:
false },
{ subid: '6', category_id:'2', name: 'Music Production', selected:
false },
{ subid: '7', category_id:'2', name: 'Webdesign', selected: false
},
{ subid: '8', category_id:'2', name: 'Office', selected: false },
],
newcategories: [
{ id: '1', subcategory_id:'1', name: 'New Adventure', selected:
false },
{ id: '2', subcategory_id:'1', name: 'New Shooter', selected: false
},
{ id: '3', subcategory_id:'1', name: 'New Simulation', selected:
false },
{ id: '4', subcategory_id:'1', name: 'New Sports', selected: false
},
{ id: '5', subcategory_id:'2', name: 'New Illustration', selected: false
},
{ id: '6', subcategory_id:'2', name: 'New Music Production',
selected: false },
{ id: '7', subcategory_id:'2', name: 'New Webdesign', selected:
false },
{ id: '8', subcategory_id:'2', name: 'NewOffice', selected: false
},
],
}
});
I'm using vue-js and element-ui running on dev-server coming from vue-cli with the webpack template.
I'm trying to debounce the search value of a filterable input. In other words, I would like to debounce the :filter-method and getting the parameters query to do an ajax call
Here is the fiddle example https://jsfiddle.net/ffeohmk4/
In that example there is no debounce yet.
Problem
The function getFinalList is never triggered. I would assume since it is a computed propertyit should be triggered each time this.searchValue changes.
var Main = {
data() {
return {
searchValue : '',
filteredOptions : [],
options: [{
value: 'A',
label: 'A'
}, {
value: 'B',
label: 'B'
}, {
value: 'C',
label: 'C'
}, {
value: 'D',
label: 'D'
}, {
value: 'E',
label: 'E'
}],
value8: ''
}
},
computed : {
getFinalList () {
alert('getFinalList is called');
this.filteredOptions = this.options.filter(option => {
return option.value.toLowerCase().indexOf(this.searchValue.toLowerCase()) > -1;
})
}
},
methods : {
setSearchInput (query) {this.searchValue = query}
},
created () {
this.filteredOptions = this.options;
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
Here is a working another example https://jsfiddle.net/ffeohmk4/2/
getFinalList () {
return this.filteredOptions = this.options.filter(option => {
return option.value.toLowerCase().indexOf(this.searchValue.toLowerCase()) > -1;
})
}
<el-select v-model="searchValue" filterable placeholder="Select" :filter-method="setSearchInput">
<el-option v-for="item in getFinalList" :key="item.value" :label="item.label" :value="item.value">
</el-option>