[Vue.js + Vuetify.js] v-treeview 자식노드를 동적으로 disabled 처리하는 방법????
부모노드를 선택했을 때 자식 노드를 선택하지 못하도록 Disable 처리하고, 반대로 부모노드 선택을 해제했을 때 자식노드를 다시 선택할 수 있도록 기능 구현을 하고 있다.
사실 이런 기능은 사용자 싫수에 따른 오류를 없애기위해 필요한 기능이지, 개발자 입자에서는 필요없다고 보는 기능이다.
disable 처리가 아닌방법으로 부모노드를 선택했을 경우에 후 순위 작업으로 자식노드를 선택했을 때 선택할 수 없다는 메세지를 뛰운 후 선택해제해주는 방법도 생각해볼 수 있다.
트리를 구성하는 기본 데이터는 다음과 같다. (this.tree.originData)
[
{
"id":22,
"parentId":0,
"name":"개발부서",
"treeDepth":0,
"orderSeq":1,
"children":[
{
"id":39,
"parentId":22,
"name":"부서1",
"treeDepth":1,
"orderSeq":1,
"children":[
{
"id":69,
"parentId":39,
"name":"1234",
"treeDepth":2,
"orderSeq":1,
"children":[
]
},
{
"id":83,
"parentId":39,
"name":"부서-1-1",
"treeDepth":2,
"orderSeq":1,
"children":[
]
}
]
},
{
"id":40,
"parentId":22,
"name":"부서2",
"treeDepth":1,
"orderSeq":2,
"children":[
{
"id":41,
"parentId":40,
"name":"부서2-1",
"treeDepth":2,
"orderSeq":1,
"children":[
]
}
]
}
]
},
{
"id":39,
"parentId":22,
"name":"부서1",
"treeDepth":1,
"orderSeq":1,
"children":[
{
"id":69,
"parentId":39,
"name":"1234",
"treeDepth":2,
"orderSeq":1,
"children":[
]
},
{
"id":83,
"parentId":39,
"name":"부서-1-1",
"treeDepth":2,
"orderSeq":1,
"children":[
]
}
]
},
{
"id":40,
"parentId":22,
"name":"부서2",
"treeDepth":1,
"orderSeq":2,
"children":[
{
"id":41,
"parentId":40,
"name":"부서2-1",
"treeDepth":2,
"orderSeq":1,
"children":[
]
}
]
},
{
"id":41,
"parentId":40,
"name":"부서2-1",
"treeDepth":2,
"orderSeq":1,
"children":[
]
},
{
"id":69,
"parentId":39,
"name":"1234",
"treeDepth":2,
"orderSeq":1,
"children":[
]
},
{
"id":83,
"parentId":39,
"name":"부서-1-1",
"treeDepth":2,
"orderSeq":1,
"children":[
]
}
]
JSON데이터 정렬해주는 사이트를 이용하여 String타입의 json데이터를 정렬하였다.
트리 노드를 disable처리하기 위해서는 <v-treeview> 태그 속성 값 중에 다음 속성을 추가해준다
item-disabled="locked"
그런다음,
트리를 구성하는 데이터에 locked 값에 대한 true, false를 지정해주어야한다. 이부분을 동적으로 구현해야한다.
검색을 해보았지만 자료가 많지않아 직접구현해야했다.
<v-treeview
v-model="tree.treeData"
ref="treeview"
item-key="id"
:items="tree.itemsTree"
:active.sync="tree.active"
:selectable="isSelectTree"
:activatable="isActivatable"
:selection-type="selectionType"
:return-object="returnObject"
:disabled="isDisabled"
@update:active="selectNode"
@input="selectCheckBox"
rounded
hoverable
item-disabled="locked">
>
<template slot="label" slot-scope="{ item, open, active }">
<div @click="active ? $event.stopPropagation() : null">
<v-icon v-if="!item.icon">{{ open ? 'mdi-folder-open' : 'mdi-folder' }}</v-icon>
<v-icon v-else>{{ 'mdi-'+ item.icon }}</v-icon>
{{ item.name }}
</div>
</template>
</v-treeview>
data: () => ({
tree: {
treeData: [],
itemsTree: [],
choicedNode: {},
openNode: [],
active: [],
originData: [],
},
}),
........생략..............
selectCheckBox(e) {
console.log('checkbox clicked', e);
// 부모 노드값을 갖은 자식노드를 찾아 locked= true 처리 한다.
console.log(`## tmpArr = ${JSON.stringify(this.tree.originData)}`);
let tmpArr = [];
this.tree.treeData.forEach((id) => {
tmpArr = this.makeLockTreeArray(this.tree.originData, id);
});
if (tmpArr.length > 0) {
this.tree.itemsTree = tmpArr;
}
this.$emit('treeCheckClicked', this.submit());
},
makeLockTreeArray(array, treeId) {
const topLevel = 0;
const treeNodes = [];
array.forEach((item) => {
if (item.treeDepth === topLevel) {
const node = item;
node.locked = false;
node.children = this.makeLockNode(array, topLevel + 1, item.id, treeId);
treeNodes.push(node);
}
});
return treeNodes;
},
makeLockNode(array, level, parentId, treeId) {
const childNodes = [];
array.forEach((item) => {
if (item.treeDepth === level && item.parentId === parentId) {
const node = item;
if (item.parentId === treeId) {
node.locked = true;
} else {
node.locked = false;
}
node.children = this.makeLockNode(array, level + 1, item.id, treeId);
childNodes.push(node);
}
});
return childNodes;
},
그런데 초기화가 안된다. 체크 해제를 하면 원래의 값으로 돌아가는데, 트리에 반영이 안된다.
또 한가지 문제는 여러개의 부모노드를 선택하는경우 가장 마지막 노드에만 locked:true가 반영이된다는 문제가 있다.
또 하나의 문제가 있다. 트리 뎁스가 깊어지면 , 부모 노드값이 다르기 때문에 자식노드가 disabled 처리가 되지않는다.
서로 물고 있는 부모노드id값이 다르기 때문이다.
아 어떻게 하지…..
머리가 안돌아간다.
다른 방법 으로 상위 그룹을 선택 시 하위 노드가 아닌 그룹 노드 ID를 리턴하고 그룹에 하위 노드가 하나라도 선택이 안된 경우는 하위 노드 ID 리턴하도록하는 메소드
getCustomSelectNode() {
// treeview 컴포넌트의 모든 nodes 정보, object로 되어 있어서 속성 값만 array로 변경
const nodes = Object.values(this.$refs.treeview.nodes);
// 선택이 된 그룹 노드 추출
const selectParentNodes = nodes.filter((row) => {
const node = row;
return node.children.length && node.isSelected;
});
return nodes.reduce((acc, row) => {
const node = row;
let mat = [];
// 현재 노드의 부모 노드가 선택됐는지 확인
if (selectParentNodes.length) {
mat = selectParentNodes.filter((prnt) => {
const parentNode = prnt;
return parentNode.item.id === node.item.parentId;
});
}
// 노드가 선택되어 있고 부모 노드가 없거나 선택이 안된 경우 push
if (node.isSelected && !mat.length) {
acc.push(this.returnObject ? node.item : node.item.id);
}
return acc;
}, []);
},
[REFERENCE]