Show only enabled item in v-treeview - vue.js

I'm using v-treeview and i have items like that:
[
{
id: 1,
name: 'name 1',
disabled: false,
children: [
{
id: 2,
name: 'name 2',
disabled: false,
children: [
{
id: 3,
name: 'name 3',
disabled: false
}
]
},
{
id: 4,
name: 'name 4',
disabled: false,
children: [
{
id: 5,
name: 'name 5',
disabled: true
}
]
},
{
id: 6,
name: 'name 6',
disabled: true,
children: [
{
id: 7,
name: 'name 7',
disabled: true
}
]
}
]
}
]
that i want is, only showing the items with disabled false; without passing by filter data to send to v-treeview;
I already tried on slot on not showing any data when disabled is true but the the item set blank space:
<template v-slot:label="{item}" >
<v-container v-if="!item.disabled">
{{ item.name }}
</v-container>
</template>
Some items is provided with v-select, it allow to switch the disabled value of children items, so can't use filter computed cause i have no access of the children with disabled true;

You can use computed in order to create a dynamic variable:
computed: {
visibleElements: function() {
// filter here only entries you are interested to show
let visibleElements = elements.map(el => {
:
:
});
return visibleElements;
}
}

Related

Vue 3 TreeView Specify icon for Root

I'm using vue 3 treeview to show the list of buildings, real state etc. now I want to specify an icon for root which is home icon, and the first parent to be building, and the children to be store.
but as I saw treeview only had open & close Icon to handle :( can anyone tell me how to customize it?
<blocks-tree class="justify-content-center d-flex" :data="treeData"
:horizontal="treeOrientation==='1'"
:config="config"
:collapsable="true">
<template #node="{data}">
<span>
<input type="checkbox"
:checked="selected.indexOf(data.some_id)> -1"
#change="(e)=>toggleSelect(data,e.target.checked)"/>
{{data.label}}
</span>
</template>
</blocks-tree>
the data:
let treeData = reactive({
label: '4-4-2-2-0-0-0',
expand: true,
some_id: 1,
icon: 'fa fa-home',
children: [
{ label: '4-4-2-2-1-0-0', some_id: 2, icon: 'fa fa-building', },
{ label: '4-4-2-2-1-0-1', some_id: 3, icon: 'fa fa-building',},
{
label: '4-4-2-2-1-0-2',
some_id: 4,
expand: false,
children: [
{ label: '4-4-2-2-1-1-2', some_id: 5 },
{
label: '4-4-2-2-1-2-2',
some_id: 6,
expand: false,
children: [
{ label: 'واحد 1', some_id: 7 },
{ label: 'واحد 2', some_id: 8 },
]
},
]
},
]
});
and config:
config: {
roots: ['1'],
parentIcon: {
type: 'class',
class: 'fa fa-home'
}
}

Show Hide Vuejs Element

hello, I have a dilemma, trying to show and hide content from a list
I have an object in data
{
types : {
key_1 : { code: 'code_1', text: 'hello 1', show: false },
key_2 : { code: 'code_2', text: 'hello 2', show: false },
key_3 : { code: 'code_3', text: 'hello 3', show: false },
key_4 : { code: 'code_4', text: 'hello 4', show: false },
key_5 : { code: 'code_5', text: 'hello 5', show: false },
}
}
and another in localStorage
[
{ key_6 : { code: 'code_6', text: 'hello 6', show: false } },
{ key_7 : { code: 'code_7', text: 'hello 7', show: false } },
{ key_8 : { code: 'code_8', text: 'hello 8', show: false } },
{ key_9 : { code: 'code_9', text: 'hello 9', show: false } },
]
in created
created: function(){
let datas = JSON.parse(window.localStorage.getItem('types'));
datas.forEach( o => {
this.types[o.code] = {
text : o.text,
show : false,
};
});
},
it works fine this.types, there are both lists
now there's an HTML
<ul>
<li v-for="(v,k) in types" :key="k">
<a #click="opClo(k)">
<span>{{v.text}}</span>
</a>
<ol v-show="v.show">
<li>hello</li>
</ol>
</li>
</ul>
in methods
opClo : function( key ){
this.types[key].show = !this.types[key].show;
},
opClo would have to show or hide the ol, but it fails, it only opens the data, the challenge doesn't open them, how can this problem be solved?
for the record if someone else has the same problem,
the datas.forEach loop when assigning data directly to the object, it is to use $set
this.$set(this.types, key, item)
This was the problem.
Anyway, I think the problem is that because you are adding the items from localStorage after the this.type property is created, the newly added items are not reactive.
see https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

Expand and collapse treeview using button | Vuetify

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

What do I have to do to import tree from element-ui with vue.js to use sloped-slot?

I want to create a vue component that displays a element-ui tree with sloped-slot.
I imported the element-ui via npm install element-ui -S and it's listed in my node_modules folder.
I try to display the tree via the following code but it doesn't work.
<template>
<div>
<h1>Testing Sloped Slot of element-ui tree with vue.js</h1>
<el-tree
:data="data"
show-checkbox
node-key="id"
default-expand-all
:expand-on-click-node="false">
<span class="custom-tree-node" slot-scope="{ node, data }">
<span><b>{{ node.label }}</b></span>
</span>
</el-tree>
</div>
</template>
<script>
import tree from 'element-ui'
export default {
name: 'chart',
data() {
return data = [{
id: 1,
label: 'Level one 1',
children: [{
id: 4,
label: 'Level two 1-1',
children: [{
id: 9,
label: 'Level three 1-1-1'
}, {
id: 10,
label: 'Level three 1-1-2'
}]
}]
}, {
id: 2,
label: 'Level one 2',
children: [{
id: 5,
label: 'Level two 2-1'
}, {
id: 6,
label: 'Level two 2-2'
}]
}];
},
}
Vue.use(tree);
</script>
You have a typo in the data() method.
Vue merges returned from data() object into "this".
So, if you have data() { return {a: '1'}; } - a became available in this.a in components, or just a in templates.
Your data() should looks like:
data() {
return {
data: [{
id: 1,
label: 'Level one 1',
children: [{
id: 4,
label: 'Level two 1-1',
children: [{
id: 9,
label: 'Level three 1-1-1'
}, {
id: 10,
label: 'Level three 1-1-2'
}]
}]
}, {
id: 2,
label: 'Level one 2',
children: [{
id: 5,
label: 'Level two 2-1'
}, {
id: 6,
label: 'Level two 2-2'
}]
}]
};
},

Remove an item from array by id

data: function(){
return {
items: [
{ id: '1', name: 'Item 1', bool: false},
{ id: '2', name: 'Item 2', bool: false},
{ id: '3', name: 'Item 3', bool: false},
{ id: '4', name: 'Item 4', bool: false}
],
checkedItems: [],
};
},
methods:
{
select: function(event, index) {
if (!this.items[index].bool) {
this.checkedItems.splice(index, 1);
} else {
this.checkedItems.push(this.items[index]);
}
}
}
When I click on the div it copies the items data into checkedItems and sets bool to true.
Is it possible to target the item id and remove that specific one from checkedItems as the current splice is removing the wrong item based off the index.
Why not use an object instead of an array, something like this:
data: function(){
return {
items: [
{ id: '1', name: 'Item 1', bool: false},
{ id: '2', name: 'Item 2', bool: false},
{ id: '3', name: 'Item 3', bool: false},
{ id: '4', name: 'Item 4', bool: false}
],
checkedItemsObj: {},
};
},
methods:
{
select: function(event, index) {
let item = this.items[index];
if (!item.bool) {
this.checkedItemsObj[item.id] = item
} else {
delete this.checkedItemsObj[item.id]
}
},
getCheckedItems: () => Object.values(data().checkedItemsObj)
}
Now to get the array of checked items anytime, you can call methods.getCheckedItems()