How to setup multiple dropdowns in vuetify - vue.js

Someone know ho to setup multiple dropdowns in vuetify
I am new to learning in this framework.
Let me explain
In this situation im need to display all categories, subcategories and parent categories
In finish result im want get something like this
Anyway thanks for help
<ul>
<li>Category
<ul>
<li>SubCategory 1.1
<ul>
<li>
Parent Category
</li>
</ul>
</li>
<li>SubCategory 1.2</li>
</ul>
</li>
(...)
</ul>

You will need to bind each dropdown to a data member.
Add a watch to the data member, and when it changes, repopulate the other dropdowns and the default value.
Setting immediate in the watcher will call the handler when loaded, before the user selects an item, and populates the initial state.
https://codepen.io/Flamenco/pen/xovKLq
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: () => ({
item: "color",
item2: "red",
items: ["color", "number"],
items2: "null"
}),
watch: {
item: {
immediate: true,
handler(value) {
if (value === "color") {
this.items2 = ["red", "blue"];
this.item2 = "red";
} else {
this.items2 = ["1", "2", "3"];
this.item2 = "1";
}
}
}
}
});
<div id="app">
<v-app>
<div style='width:3in'>
<v-select v-model='item' :items='items' label='Select 1'></v-select>
<v-select v-model='item2' :items='items2' label='Select 2'></v-select>
</div>
</v-app>
</div>

Related

Vuejs multiple active buttons

I'm trying to create a list where every list item contains a button and i want a user to be able to click multiple button. I'm generating my list like so:
<ul>
<li v-for="item in items" :key="item.id">
<button type="button">{{item.title}}</button>
</li>
</ul>
but the problem with my code is whenever a user click a button, it turns the rest of the buttons to "unclicked". been trying to play with the focus and active stats but even with just css i cant get to enable multiple select .
i did manage to change the look of the current selected button:
button:focus {
outline: none;
background-color: #6acddf;
color: #fff;
}
any idea how can i allow multiple buttons to be clicked?
to make things a bit clearer, i am going to create an AJAX call later and pass the item.id of each item where it's button is clicked
I would much rather avoid changing the data structure if possible
Well you have to store somewhere that you clicked on the clicked item.
If you can't edit the items array then you can always create a new one, like isClicked where you store those values.
new Vue({
el: '#app',
data: {
items: [{
id: 1,
title: 'foo'
},
{
id: 2,
title: 'bar'
},
{
id: 3,
title: 'baz'
}
],
isClicked: []
},
beforeMount() {
// set all values to false
this.items.forEach((item, index) => this.$set(this.isClicked, index, false))
},
methods: {
clicked(index) {
// toggle the active class
this.$set(this.isClicked, index, !this.isClicked[index])
}
}
})
.active {
background: red
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<div v-for="(item, index) in items" :key="index">
<button #click="clicked(index)" :class="{'active': isClicked[index]}">{{item.title}}</button>
</div>
</div>
Or you can use vuex for storing those values.
However you can just use Vues event to manipulate the classList property, like:
new Vue({
el: '#app',
data: {
items: [1, 2, 3, 4, 5, 6, 7]
}
})
.active {
color: red
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<button v-for="i in items" #click="e => e.target.classList.toggle('active')">{{ i }}</button>
</div>
But it doesn't feel right, IMHO.
Also you can use cookies or localStorage to store those states. So it's really up to you.
Use id attribute for list items to make it unique.
<ul>
<li v-for="item in items" :key="item.id" :id="item.id">
<button type="button" #click="doThis">{{item.title}}</button>
</li>
</ul>
new Vue({
el: '#app',
data: {},
methods: {
doThis() {
// Use this to access current object
}
}
});

Array of inputs, with last field always blank for new add

JSBin and Stackoverflow snippet are below.
I am trying to have a list of input components. If all input components are filled with a value (not blank), then there should be a "new blank field" visible at the end for the user to type into. When he types into it, it should make this field apart of the list above it, maintaining focus in it.
However the problem I'm having is, focus maintains in the new field, and never moves into the array. Here is my code:
JSBIN and stackoverflow snippet - https://jsbin.com/cudabicese/1/edit?html,js,output
const app = new Vue({
el: '#app',
data: {
inputs: [
{ id:'foo', value:'foo' },
{ id:'bar', value:'bar' }
]
},
methods: {
addRow(e) {
this.inputs.push({
id: Date.now(),
value: e.target.value
})
},
deleteRow(index) {
this.inputs.splice(index, 1)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="app">
<ul>
<li v-for="(input, index) of inputs">
<input type="text" v-model="input.value">
</li>
<li v-if="inputs.filter(input => !!input.value).length">
<input type="text" #input="addRow">
</li>
</ul>
</div>
I'd recommend you put the input for the list within a computed function vs directly using the data. The examples at https://v2.vuejs.org/v2/examples/ are a good place to start.

vuejs auto-filter out an array marked "Bar"

I am new vuejs but learning a lot. I Have an array of items that renders to a list perfectly fine. I do want to not display anything marked Bar? I have tried !Bar but it does not work. Whats the correct way to do this?
var app = new Vue({
el: "#demo",
data: {
items: [{
childMsg: 'Foo'
}, {
childMsg: 'Bar'
}]
}
});
<script src="https://unpkg.com/vue"></script>
<div id="demo">
<ul v-for="item in items">
<li>{{item.childMsg}}</li>
</ul>
</div>
As usual, there are several approaches. One most straightforward is to exclude the item directly within v-for element template, like this:
<li v-if="item.childMsg !== 'Bar'">{{item.childMsg}}</li>
An alternative would be creating a computed property: array of items that do not match the pattern. Then you can rebase your v-for onto that property. Here's how it can be done:
var app = new Vue({
el: "#demo",
data: {
exclude: '',
items: [{
childMsg: 'Foo'
}, {
childMsg: 'Bar'
}]
},
computed: {
filteredItems() {
return this.items.filter(x => x.childMsg !== this.exclude);
}
}
});
<script src="https://unpkg.com/vue"></script>
<div id="demo">
<label>Exclude word... <input type="text" v-model="exclude" /></label>
<ul v-for="item in filteredItems">
<li>{{item.childMsg}}</li>
</ul>
</div>

VueJS: Why v-model does not work with a vuejs filter

Why v-model does not work with a filter getUppercase in <input v-model="filterText | getUppercase">
HTML
<template>
<div class="wrapper">
Check if fruit exist: <input v-model="filterText | getUppercase">
<ul v-for="fruit in filteredFruits">
<li> {{ fruit }} </li>
</ul>
</div>
</template>
VueJS
export default {
name: "filterText",
data() {
return {
msg: "Welcome to Your Vue.js App",
filterText: "",
fruits: ["Apple", "Banana", "Orange", "PineApple", 'Pina Colada']
};
},
computed: {
filteredFruits: function() {
var vm = this;
return vm.fruits.filter(function(item) {
return item.match(vm.filterText)
});
}
},
filters: {
getUppercase: function(obj) {
return this.obj.toUpperCase();
}
}
};
I can see what you are trying to do, however, because of the two way binding when using v-model, it will be better to just apply the getUppercase filter when displaying.
Your template would be something like this:
<template>
<div class="wrapper">
Check if fruit exist: <input v-model="filterText">
<ul v-for="fruit in filteredFruits">
<li> {{ fruit | getUppercase}} </li>
</ul>
</div>
</template>
But if you still wish to transform the filterText model value, you can use a directive. In that case, your VueJS code will be something like :
Vue.directive('getUppercase', {
twoWay: true, // this transformation applies back to the filterText
bind: function () {
var self = this;
self.handler = function () {
self.set(self.el.value.toUpperCase());
}
self.el.addEventListener('input', self.handler);
},
unbind: function () {
this.el.removeEventListener('input', this.handler);
}
});
Now use this directive in your template like :
<input v-model="filterText" v-get-uppercase="filterText">
It will do the same thing as <input v-model="filterText | getUppercase">
Two ways filters are replaced in vue.js please read the docs for more information.It is good to know.
However,as i understood you want to implement a search in array.See it in action here, or take a look below
<div id="app">
Check if fruit exist: <input v-model="filterText">
<ul v-for="fruit in filteredFruits">
<li> {{ fruit }} </li>
</ul>
</div>
new Vue({
el: "#app",
data: {
filterText: "",
fruits: ["Apple", "Banana", "Orange", "PineApple", 'Pina Colada']
},
computed: {
filteredFruits() {
return this.fruits.filter(item => item.toLowerCase().match(this.filterText.toLowerCase()))
}
}
})

Vue custom filtering input component

I'am trying to create a component that have 'just' an text input. String typed in this input will be used to filter a list. My problem is that I cannot handle how to share this filter string between my component and the main app that contains the list to filter.
I tried several things and most of the time I get the error :
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value
So I looked Vuex but I thinks it cannot help in this case because I can have several filter component used in he same page for different list, and I don't want them to be synchronized ^^
Here is what I have:
The filter component
<script type="x/template" id="filterTpl">
<div>
<span class="filter-wrapper">
<input type="search" class="input input-filter" v-model.trim="filter" />
</span>
</div>
</script>
<script>
Vue.component('list-filter', {
props: {
filter: String
}
template: '#filterTpl'
});
</script>
And my main app:
<div id="contacts">
<list-filter :filter="filter"></list-filter>
<ul class="contacts-list managed-list flex">
<li class="contact" v-for="contactGroup in filteredData">
[...]
</li>
</ul>
</div>
<script>
var contactsV = new Vue({
el: '#contacts',
data: {
filter: "",
studyContactsGroups: []
},
computed: {
filteredData: function(){
// Using this.filter to filter the studyContactsGroups data
[...]
return filteredContacts;
}
}
});
</script>
Thanks for any help or tips :)
You can synchronize child value and parent prop either via explicit prop-event connection or more concise v-bind with sync modifier:
new Vue({
el: '#app',
data: {
rawData: ['John', 'Jane', 'Jim', 'Eddy', 'Maggy', 'Trump', 'Che'],
filter: ''
},
components: {
'my-input' : {
// bind prop 'query' to value and
// #input update parent prop 'filter' via event used with '.sync'
template: `<input :value="query" #input="updateFilter">`,
props: ['query'],
methods: {
updateFilter: function(e) {
this.$emit('update:query', e.target.value) // this is described in documentation
}
}
}
},
computed: {
filteredData: function() {
// simple filter function
return this.rawData.filter(el => el.toLowerCase()
.match(this.filter.toLowerCase()))
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<my-input :query.sync="filter"></my-input>
<hr>
<ul>
<li v-for="line in filteredData">{{ line }}</li>
</ul>
</div>