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
},
],
}
});
Related
I am currently trying to show/hide dynamically with a bootstrap-vue table (https://bootstrap-vue.js.org/docs/components/table).
So far, I only managed to hide the header but the cells won't disappear, which is a problem because the cells are not in front of the good headers (the numbers should be under days and 'ingredient' should be under item.
Here what's 'worked':
fields: [
{key: "day", label: "Day",sortable: true, thStyle:"display:none"},
{key: "item", label: "Item",sortable: true}
]
I was wondering if it was possible to maybe do that outside of vueJS, and change the properties of the column with CSS directly..
Thanks for the help !
Louis
You could add an additional property to your fields. For example visible and create a computed property that filters out all fields with visible: false.
That way you can simply toggle this property to show/hide your columns.
window.onload = () => {
new Vue({
el: '#app',
computed: {
visibleFields() {
return this.fields.filter(field => field.visible)
}
},
data() {
return {
items: [
{ id: 1, first: 'Mike', last: 'Kristensen', age: 16 },
{ id: 2, first: 'Peter', last: 'Madsen', age: 52 },
{ id: 3, first: 'Mads', last: 'Mikkelsen', age: 76 },
{ id: 4, first: 'Mikkel', last: 'Hansen', age: 34 },
],
fields: [
{ key: 'id', label: 'ID', visible: true },
{ key: 'first', label: 'First Name', visible: true },
{ key: 'last', label: 'Last Name', visible: true },
{ key: 'age', label: 'Age', visible: true },
]
}
}
})
}
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.2.2/dist/bootstrap-vue.min.js"></script>
<div id='app'>
<b-checkbox
:disabled="visibleFields.length == 1 && field.visible"
v-for="field in fields"
:key="field.key"
v-model="field.visible"
inline
>
{{ field.label }}
</b-checkbox>
<br /><br />
<b-table :items="items" :fields="visibleFields" bordered>
</b-table>
</div>
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();
}
})
I'm trying to create a search page (my-site.com/search) and need to pass 3 optional dynamic params to this url on click.
The issue is on click something is removing 'search' from the path and taking me to the root path - my-site.com/. I'm having trouble figuring out what's causing it.
paths.js
const tagToParam = {
postname: ':slug',
search: ':term?/:author?/:topic?'
}
const paginateParam = ':page(page\/\\d+)?'
export default {
postsPageWithSearch: (slug) => slug ? `/${slug}/${tagToParam.search}/${paginateParam}` : `/${paginateParam}`,
}
routes.js
import Search from '#/components/Search'
import paths from './paths'
{
path: paths.postsPageWithSearch('search') + '/',
component: Search,
name: 'Search',
meta: { bodyClass: 'search' },
props: route => (Object.assign(route.params, {
term: route.params.term,
author: route.params.author,
topic: route.params.topic,
page: pageFromPath(route.path)
} ))
},
Search.vue
<template>
<main class="site-content">
<div class="container">
<div class="advanced-search">
<form #click.prevent>
<input type="text"
name="searchTerm"
placeholder="Search title..."
tabindex="1"
v-model="searchTerm">
<select v-model="searchAuthor">
<option value="">All</option>
<option
v-for="author in authors"
:value="author.id"
:key="author.id">{{ author.name }}</option>
</select>
<select v-model="searchTopic">
<option value="">All</option>
<option
v-for="topic in topics"
:value="topic.id"
:key="topic.id">{{ topic.name }}</option>
</select>
<button class="button" type="submit" #click="submitSearch()">Search</button>
</form>
</div>
<section v-if="posts">
<post-item
v-for="post in posts"
:key="post.id"
:post="post"
:postmeta=false
/>
</section>
</div>
</main>
</template>
<script>
import PostItem from '#/components/template-parts/PostItem'
export default {
name: 'Search',
components: {
PostItem,
},
props: {
page: {
type: Number,
required: true
},
term: {
type: String,
required: true
},
author: {
required: true
},
topic: {
required: true
},
},
data() {
return {
postsRequest: {
type: 'quote',
params: {
per_page: 5,
search: this.term,
authors: this.author,
tags: this.topic,
page: this.page
},
showLoading: true
},
totalPages: 0,
authorsRequest: {
type: 'authors',
params: {
per_page: 100,
},
},
topicsRequest: {
type: 'tags',
params: {
per_page: 100,
},
},
searchTerm: '',
searchAuthor: '',
searchTopic: ''
}
},
computed: {
authors () {
return this.$store.getters.requestedItems(this.authorsRequest)
},
topics () {
return this.$store.getters.requestedItems(this.topicsRequest)
},
posts() {
return this.$store.getters.requestedItems(this.postsRequest)
}
},
methods: {
getAuthors() {
return this.$store.dispatch('getItems', this.authorsRequest)
},
getTopics() {
return this.$store.dispatch('getItems', this.topicsRequest)
},
getPosts() {
return this.$store.dispatch('getItems', this.postsRequest)
},
setTotalPages() {
this.totalPages = this.$store.getters.totalPages(this.postsRequest)
},
submitSearch() {
this.$router.replace({
name: "Search",
params: {
term: this.searchTerm,
author: this.searchAuthor,
tags: this.searchTopic
}
})
}
},
created() {
this.getAuthors()
this.getTopics()
this.getPosts().then(() => this.setTotalPages())
},
}
</script>
It looks like the <form> element has #click.prevent. Try putting the #click.prevent on your submit button.
Does anyone know how to actually display the text value from multiple dependent select fields?
I need option 1 to list a set of parent options. When an Option 1 is selected, it will determine the values available in Option 2 select field.
I then want the text value associated with the selected option to be displayed below the select field.
<template>
<div>
<panel class="main-content">
<div>
<b-form-select v-model="selected" :options="options" class="mb-3" />
<div>Selected: <strong>{{ selected }}</strong></div>
</div>
<div>
<b-form-select v-model="selected" :options="options" class="mb-3" />
<div>Selected: <strong>{{ selected }}</strong></div>
</div>
</panel>
</div>
</template>
<script>
export default {
data () {
return {
selected: null,
options: [
{ value: null, name: 'opt', text: 'Select One' },
{ value: 'option1', name: 'mys', text: 'Carbohydrates' },
{ value: 'option2', name: 'hkong', text: 'Fibre' },
{ value: 'option3', name: 'spore', text: 'Fat' }
]
}
}
}
</script>
Kindly assist since it's something new for me in VueJs.
This is working in VueJS (tested). I was a little off about how the b-form-select element works, but this will give you the results you need.
If you are building the options manually, maybe just make a JSON file or a Component that returns these sets of options and subOptions and import it rather than putting all the options into your template (Cleaner Code).
<script>
export default {
data () {
return {
option1Selected: null,
option2Selected: null,
options: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option1',
name: 'mys',
text:'Carbohydrates',
},
{
value: 'option2',
name: 'hkong',
text: 'Fibre',
},
{
value: 'option3',
name: 'spore',
text: 'Fat',
},
],
subOptions: {
option1: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option1-1',
name: 'o1-1Name',
text: 'Option 1-1 Text',
},
{
value: 'option1-2',
name: 'o1-2Name',
text: 'Option 1-2 Text',
},
{
value: 'option1-3',
name: 'o1-3Name',
text: 'Option 1-3 Text',
},
],
option2: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option2-1',
name: 'o2-1Name',
text: 'Option 2-1 Text',
},
{
value: 'option2-2',
name: 'o2-2Name',
text: 'Option 2-2 Text',
},
{
value: 'option2-3',
name: 'o2-3Name',
text: 'Option 2-3 Text',
},
],
option3: [
{
value: null,
name: 'opt',
text: 'Select One',
},
{
value: 'option3-1',
name: 'o3-1Name',
text: 'Option 3-1 Text',
},
{
value: 'option3-2',
name: 'o3-2Name',
text: 'Option 3-2 Text',
},
{
value: 'option3-3',
name: 'o3-3Name',
text: 'Option 3-3 Text',
},
],
}
}
},
computed: {
option1text () {
for (const key in this.options) {
if (this.options[key].value === this.option1Selected) {
return this.options[key].text;
}
}
},
option2text () {
if (this.option1Selected != null) {
for (const key in this.subOptions[this.option1Selected]) {
if (this.subOptions[this.option1Selected][key].value === this.option2Selected) {
return this.subOptions[this.option1Selected][key].text;
}
}
}
}
},
}
</script>
<template>
<div>
<panel class="main-content">
<div>
<b-form-select v-model="option1Selected" :options="options" class="mb-3" />
<div>Selected: <strong>{{ option1text }}</strong></div>
</div>
<div v-if="option1Selected != null">
<b-form-select v-model="option2Selected" :options="subOptions[option1Selected]" class="mb-3" />
<div>Selected: <strong>{{ option2text }}</strong></div>
</div>
</panel>
</div>
</template>
Note I have updated code to properly reflect exactly what you were asking for in the question: the Text value of the option.
I need to do multi-category filtering with vuejs 2. I struggled a bit for this but the filtering process is not working.
I know how to do filtering operations with the computed method.
When I try this, I can only list the data for a single category.If I choose another category, the data comes out empty.I do not understand where I am making mistakes?
My Example : https://jsfiddle.net/a3x374qy/9/
new Vue({
el: '#app',
data: {
checkedEatCategories:[],
eatCategories : [
{
id:1,
title: 'Category 1',
},{
id:2,
title: 'Category 2',
},{
id:3,
title: 'Category 3',
},{
id:4,
title: 'Category 4',
},{
id:5,
title: 'Category 5',
}
],
posts: [
{
id:1,
title:'Product 1',
eat_categories: [
{
id:1,
}
]
},
{
id:2,
title:'Product 2',
eat_categories: [
{
id:1,
},
{
id:2,
},
{
id:3,
}
]
},
{
id:3,
title:'Product 3',
eat_categories: [
{
id:1,
},
{
id:5,
}
]
}
]
},
computed: {
filteredPlaces: function () {
return this.posts.filter((j) => {
return (j.eat_categories.includes(this.checkedEatCategories));
});
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<ul>
<li v-for="eatCategory in eatCategories">
<label>
<input type="checkbox" :value="eatCategory.id" v-model="checkedEatCategories">
<span class="title">{{eatCategory.title}}</span>
</label>
</li>
</ul>
<ul>
<li v-for="post in posts">
{{ post.title }}
</li>
</ul>
</div>
A couple of issues here.
You're looping through posts instead of filteredPlaces in your template
.includes() doesn't accept an array. Try combining it with .some()
new Vue({
el: '#app',
data: {
checkedEatCategories: [],
eatCategories: [{
id: 1,
title: 'Category 1',
}, {
id: 2,
title: 'Category 2',
}, {
id: 3,
title: 'Category 3',
}, {
id: 4,
title: 'Category 4',
}, {
id: 5,
title: 'Category 5',
}],
posts: [{
id: 1,
title: 'Product 1',
eat_categories: [{
id: 1,
}]
},
{
id: 2,
title: 'Product 2',
eat_categories: [{
id: 1,
},
{
id: 2,
},
{
id: 3,
}
]
},
{
id: 3,
title: 'Product 3',
eat_categories: [{
id: 1,
},
{
id: 5,
}
]
}
]
},
computed: {
filteredPlaces: function() {
return this.posts.filter(post =>
post.eat_categories.some(tag =>
this.checkedEatCategories.includes(tag.id)
)
)
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<ul>
<li v-for="eatCategory in eatCategories">
<label>
<input type="checkbox" :value="eatCategory.id" v-model="checkedEatCategories">
<span class="title">{{eatCategory.title}}</span>
</label>
</li>
</ul>
<ul>
<li v-for="post in filteredPlaces">
{{ post.title }}
</li>
</ul>
</div>