I'm using last version of vue-js and element-ui whose documentation can be found here.
Context
I want to display a table containing some information about interested and attending people for a given date and room
Issue
I do not manage to display the attending and interested for each room and for each date.
The main problem is how to loop through each room
https://jsfiddle.net/k7Lzv38b/
Data
tableData: [{
date: 'Jan 2017',
rooms: [{
name: 'Room A',
attending: 10,
interested: 5
}, {
name: 'Room B',
attending: 10,
interested: 0
}]
}, {
date: 'Feb 2017',
rooms: [{
name: 'Room A',
attending: 10,
interested: 5
}, {
name: 'Room B',
attending: 10,
interested: 0
}]
}]
var Main = {
data() {
return {
tableData: [{
date: 'Jan 2017',
rooms: [{
name: 'Room A',
attending: 10,
interested: 5
}, {
name: 'Room B',
attending: 5,
interested: 10
}]
}, {
date: 'Feb 2017',
rooms: [{
name: 'Room A',
attending: 0,
interested: 5
}, {
name: 'Room B',
attending: 5,
interested: 15
}]
}, {
date: 'Mar 2017',
rooms: [{
name: 'Room B',
attending: 5
}]
}]
}
},
computed: {
rooms() {
let rooms = {}
this.tableData.forEach(row => {
row.rooms.forEach(room => {
rooms[room.name] = 1
})
})
return Object.keys(rooms)
}
},
methods: {
cellFormatter(row, col) {
let key = JSON.parse(col.property)
let d = row.rooms.find(r => r.name === key.room)
if (d && d[key.property]) {
return d[key.property]
}
return '0 '
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.0.5/lib/theme-chalk/index.css");
.container {
display: flex;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.0.5/lib/index.js"></script>
<div id="app">
<template>
<div class='container'>
<el-table :data="tableData">
<el-table-column prop="date" label="Date" align="center"></el-table-column>
<el-table-column label="Rooms" align="center">
<el-table-column :label="room" prop="rooms" align="center" v-for="room in rooms" key="room">
<el-table-column label="Attending" :prop="JSON.stringify({room, property:'attending'})" align="center" :formatter="cellFormatter">
</el-table-column>
<el-table-column label="Intereted" :prop="JSON.stringify({room, property:'interested'})" align="center" :formatter="cellFormatter">
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
</div>
</template>
</div>
To show nested data without looping use:
columns: [
{ prop: 'user_id', label: 'User ID' },
{ prop: 'market', label: 'Market ID', render: row => row.market.mkt_id },
{ prop: 'market', label: 'Pair', render: row => row.market.mkt_name },
{ prop: 'exchange', label: 'Exchange ID', render: row => row.exchange.exch_id },
{ prop: 'exchange', label: 'Exchange', render: row => row.exchange.exch_name }
]
JSON:
{
"user_id": 4,
"type_id": 1,
"market": {
"id": 270,
"mkt_id": 5946,
"mkt_name": "AEX",
},
"exchange": {
"id": 5,
"exch_id": 15,
"exch_name": "NL",
}
}
If there are only two rooms: A and B,
maybe you can simple use this 'prop' for the columns:
prop="rooms[0].attending"
prop="rooms[0].interested"
index 0 for room A and index 1 for room B
Related
I wanted to create a drop-down menu options in v-data-table
<v-data-table
:headers="headers"
:items="res"
:options.sync="options"
:server-items-length="totalRes"
:loading="loading"
loading-text="Loading ..... Please wait"
:footer-props="{
itemsPerPageOptions: [5, 10, 20, 40],
itemsPerPageText: 'Res per page',
}"
class="elevation-23"
>
</v-data-table>
data () {
return {
res: [],
totalRes: 0,
search: '',
loading: false,
options: {
page: 1,
itemsPerPage: 40,
},
headers: [
{ text: 'Name', value: 'fullName' },
{ text: 'Med', value: 'med' },
{ text: 'Start Date', value: 'startDate' },
{ text: 'Create ', value: '' },
],
}
},
Here I have a field in header Create in that field I want to show a list of drop-down say for now ['A', 'B', 'C'] and on clicking on any options among the list I wanted to route to certain routes. How do I do it ?
Vuetify v-data-table provides a slot for each of the values. I updated your example by giving the last column the name path so that it may be used in the item slot.
I added the v-select so that you get the drop down effect.
Codepen
<v-data-table
:headers="headers"
:items="res"
item-key="Name"
class="elevation-23"
>
<template v-slot:item.path="{ item }">
<v-select
v-model="cSel"
:items="item.path"
></v-select>
</template>
</v-data-table>
data () {
return {
expanded: [],
singleExpand: false,
cSel: 'A',
res: [
{
fullName: 'name 1',
med: 'med 1',
startDate: 'start date 1',
path: ['A', 'B', 'C', 'D'],
},
],
totalRes: 0,
search: '',
loading: false,
options: {
page: 1,
itemsPerPage: 40,
},
headers: [
{ text: 'Name', value: 'fullName' },
{ text: 'Med', value: 'med' },
{ text: 'Start Date', value: 'startDate' },
{ text: 'Create ', value: 'path', width: '200' },
],
}
For what you are trying to do the expanded row would work to place the links, but if you wanted to have custom data display (the data is in rows, or are other conversions needed) then you may want to consider the named slot.
Regards!
;-J
Have you tried Expandable row: https://vuetifyjs.com/en/components/data-tables#expandable-rows ?
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();
}
})
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 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>
Suppose I'm trying to make a simple questionnaire, where the user answers a list of questions.
new Vue(
{
el: "#app",
data:
{
questions:
[
{
id: 1,
name: "What is your favorite color?",
selectedId: 2,
choices:
[
{ id: 1, name: "red" },
{ id: 2, name: "green" },
{ id: 3, name: "blue" },
]
},
...
]
}
});
How do I go about making a question component with two-way binding. That is, if the user swaps their favorite color from green to red, by clicking on the respective input, the selectedId will automatically update. I'm not very clear on how v-model works within a component. Does it only have access to the components data? Also, I don't understand the difference between props/data.
There are lots of ways you can approach this, here's my attempt:
let id = 0;
Vue.component('question', {
template: '#question',
props: ['question'],
data() {
return {
radioGroup: `question-${id++}`,
};
},
methods: {
onChange(choice) {
this.question.selectedId = choice.id;
},
isChoiceSelected(choice) {
return this.question.selectedId === choice.id;
},
},
});
new Vue({
el: '#app',
data: {
questions: [
{
title: 'What is your favorite color?',
selectedId: null,
choices: [
{ id: 1, text: 'Red' },
{ id: 2, text: 'Green' },
{ id: 3, text: 'Blue' },
],
},
{
title: 'What is your favorite food?',
selectedId: null,
choices: [
{ id: 1, text: 'Beans' },
{ id: 2, text: 'Pizza' },
{ id: 3, text: 'Something else' },
],
},
],
},
});
.question {
margin: 20px 0;
}
<script src="https://rawgit.com/yyx990803/vue/master/dist/vue.js"></script>
<div id="app">
<question v-for="question of questions" :question="question"></question>
</div>
<template id="question">
<div class="question">
<div>{{ question.title }}</div>
<div v-for="choice of question.choices">
<input type="radio" :name="radioGroup" :checked="isChoiceSelected(choice)" #change="onChange(choice)"> {{ choice.text }}
</div>
<div>selectedId: {{ question.selectedId }}</div>
</div>
</template>