[Vuetify.js] 서버에서 불러온 데이터로 Treeview 노드 items Array 데이터 생성 방법
신규프로젝트에서 트리뷰 작업을 해야하는 상황에 놓였다.
그리고 어제 vuetify.js 의 트리뷰 컴포넌트에 대한 기술검토를 하였다.
그리고 오후 부터 트리노드 생성을 위해 데이터베이스로부터 불러온 트리용 쿼리 결과를
Treeview에 맞도록 가공하는 작업을 하였다.
DB의 쿼리와 조회결과 데이터는 다음과 같다.
2일 기술검토하며 결국 날코딩으로 가닥을 잡고 삽질 끝에 원하는 결과물을 생성하였다.
if (data !== undefined) {
// 1. 자식노드를 찾아서 각각의 부모 노드와 병합하여 새로운 배열 생성
for (let i = 0; i < data.length; i += 1) {
const row = data[i];
tempArrList = [];
for (let j = 0; j < data.length; j += 1) {
const secondRow = data[j];
if (row.id === secondRow.parentId) {
tempArrList.push(secondRow);
}
}
if (tempArrList.length > 0) {
const newArr = Object.assign({}, row, { children: tempArrList });
tempList.push(newArr);
console.log(`##concat = ${JSON.stringify(newArr)}`);
}
}
// 2. 새로운 배열에서 자식노드를 체크하여 부모노드와 자식 노드를 병합하여 새로운 배열 생성
tartList.push(tempList);
// tartList = tempList;// 저장소 공유됨!!
for (let i = 0; i < tempList.length; i += 1) {
const row = tempList[i];
const targetRow = tempList[i];
console.log(`##비교대상 = ${JSON.stringify(targetRow)}`);
console.log(`## row.children.length = ${row.children.length}`);
if (row.children.length > 0) {
for (let j = 0; j < row.children.length; j += 1) {
const childrenRow = row.children[j];
console.log(`##childrenRow = ${JSON.stringify(childrenRow)}`);
for (let h = 1; h < tempList.length; h += 1) { // 최상위 노드 제외
const secondRow = tempList[h];
console.log(`### childrenRow 비교대상 = ${JSON.stringify(secondRow)}`);
if (secondRow.id === childrenRow.id) { // secondRow.id === childrenRow.parentId
console.log(`### 삭제 대상 secondRow = ${JSON.stringify(secondRow)}`);
console.log(`### childrenRow = ${JSON.stringify(childrenRow)}`);
secondList.push(secondRow);
// 병합한 건은 제거: 버그 발생
// tartList = tartList.filter(item => item !== secondRow);
// console.log(`##tartList 병합건 제거후 = ${JSON.stringify(tartList)}`);
}
// else {
// // 미존재시 추가
// console.log(`존재여부 체크 : ${childrenRow in secondList}`);
// secondList.push(childrenRow);
// }
}
}
// console.log(`##secondList = ${JSON.stringify(secondList)}`);
// console.log(`##secondList.length = ${JSON.stringify(secondList.length)}`);
if (secondList.length > 0) {
// let newArr = [];
// newArr = Object.assign({}, secondList[0], secondList[1]);
for (let x = 0; x < secondList.length; x += 1) {
// console.log(`##치환 대상 = ${JSON.stringify(secondList[x])}`);
targetRow.children[x] = secondList[x];
}
// console.log(`##치환row2 = ${JSON.stringify(row2)}`);
// console.log(`##치환row2 = ${JSON.stringify(row2)}`);
tartList[i] = targetRow; // 치환
secondList = [];
// row2.children = '';
}
} // if
}
// console.log(`##중복 제거 전 tartList.length = ${JSON.stringify(tartList.length)}`);
// console.log(`##중복 제거 전 tartList = ${JSON.stringify(tartList)}`);
tartList.splice(1, tartList.length);
// console.log(`##중복 제거 후 tartList.length = ${JSON.stringify(tartList.length)}`);
// console.log(`##중복 제거 후 tartList = ${JSON.stringify(tartList)}`);
// 중복 노드 제거
// eslint-disable-next-line max-len
// const uniqueArr = tempList.filter((element, index) => tempList.indexOf(element) === index);
// console.log(`##uniqueArr = ${JSON.stringify(uniqueArr)}`);
// console.log(`##중복 제거 전 tartList = ${JSON.stringify(tartList)}`);
}
console.log(`##tartList = ${JSON.stringify(tartList)}`);
this.data.treeItems = tartList;
원하는 결과물을 2일만에 만들었으나 문제가 발생했다.
기획서 상에 내용을 보니 트리의 순서를 변경할 수 있다는 스크립트와 컬럼이 존재했다.
그래서 정렬타입으로 쿼리를 order by 한 후에 가져온 후 트리 데이터를 가공하도록 만든 위 스크립트를 돌려보니
제대로 동작하지 않았다.
잘못된 부분을 찾기 위해 또 찾아 헤매는 사이에 팀장님이 오셔서
트리 데이터 좀 보자고 하셨고, DB에서 불러온 데이터를 JSON타입으로 보냈다.
트리 레벨 값이 없다고 하시며 레벨값을 달라고 하셨다.
그러나 나는 우리가 사용하는 뷰티파이에서 제공하는 treeview는 뎁스를 사용하지 않는 구조여서 제외시켰다고 했지만
우리가 사용하는 다른 화면들에서 트리 뎁스(레벨)별로 데이터를 가져와야하는 부분들이 있다고 했다.
헉, 이건 몰랐기에 나는 뎁스를 무시하고 스크립트를 짜고 있었던 것이다.
뎁스를 추가해서 팀장님에게 기본 데이터를 드렸다.
원본데이터:
[{"id":0,"parentId":-1,"name":"전체","treeDepth":0,"orderSeq":0},
{"id":1,"parentId":0,"name":"제품1","treeDepth":1,"orderSeq":1},
{"id":9,"parentId":0,"name":"제품4","treeDepth":1,"orderSeq":1},
{"id":2,"parentId":0,"name":"제품2","treeDepth":1,"orderSeq":2},
{"id":8,"parentId":0,"name":"제품3","treeDepth":1,"orderSeq":3},
{"id":10,"parentId":1,"name":"제품1-4","treeDepth":2,"orderSeq":1},
{"id":3,"parentId":1,"name":"제품1-1","treeDepth":2,"orderSeq":1},
{"id":4,"parentId":1,"name":"제품1-2","treeDepth":2,"orderSeq":2},
{"id":5,"parentId":2,"name":"제품2-1","treeDepth":2,"orderSeq":2},
{"id":6,"parentId":1,"name":"제품1-3","treeDepth":2,"orderSeq":3},
{"id":7,"parentId":5,"name":"제품2-1-1","treeDepth":3,"orderSeq":1}]
그리고 얼마쯤 지났을까…
1시간도 안지났는데
이걸로 돌려보라고 하신다.
[
"id":0,"name":"전체"
,"children":[{"id":1,"name":"제품1","children":[{"id":10,"name":"제품1-4","children":[]}
,{"id":3,"name":"제품1-1","children":[]},{"id":4,"name":"제품1-2","children":[]}
,{"id":6,"name":"제품1-3","children":[]}]},{"id":9,"name":"제품4","children":[]}
,{"id":2,"name":"제품2","children":[{"id":5,"name":"제품2-1"
,"children":[{"id":7,"name":"제품2-1-1","children":[]}]}]}
,{"id":8,"name":"제품3","children":[]}]}]
lint 때문에 오류가 발생하여 확인이 불가했다.
그래서 결국 스크립트를 던져 주시며 돌려보라고 했다.
function clickTest() {
var topLevel = 0;
var treeNodes = [];
array.forEach((item) => {
if (item.treeDepth === topLevel ) {
var node = {};
node.id = item.id;
node.name = item.name;
node.children = makeNode(topLevel + 1, item.id);
treeNodes.push(node);
}
});
console.log(`${JSON.stringify(treeNodes)}`);
}
function makeNode(level, parentId){
var childNodes = [];
array.forEach((item) => {
if (item.treeDepth === level
&& item.parentId === parentId) {
var node = {};
node.id = item.id;
node.name = item.name;
node.children = makeNode(level+1, item.id);
childNodes.push(node);
}
});
return childNodes;
}
팀장님이 보내준 스크립트를 보고 한 대 맞은 느낌이 들었다. 트리 구현 방식은 동일하다는 것을 잊고 있었다. 이 작업을 2013년 겨울에 kendo ui로 신규 프로젝트를 하면서 트리 관련 구현을 했었지만 어떻게 구현했었는지조차 기억나지 않았다. 그러나 팀장님이 보내준 스크립트를 보니 그때 만든 스크립트와 거의 동일한 구조임을 한눈에 알아볼 수 있었다.
팀장님이 보내준 스크립트로 돌려보는데 결과물은 제대로 나왔다. 팀장님과 함께 결과물을 보는 순간…..
기쁨도 잠깐……무슨 삽질을 한것일까? 검색방향을 좀 달리했더라면 하는 생각도 들었고
flat array를 트리를 구현하기위한 nested array 로 데이터를 가공하는 스크립트를 날코딩하고 있던 나 자신에게 회의감이 왔다.
export default {
name: 'TEST',
components: {
},
data: () => ({
views: [],
treeItems: [],
},
selectionType: 'leaf', // independent
active: [],
}),
created() {
this.searchProductList();
this.selection = [];
this.treeItems = [
{
id: 0,
name: '전체',
children: [
{ id: 2, name: 'Child #1' },
{ id: 3, name: 'Child #2' },
{
id: 4,
name: 'Child #3',
children: [
{ id: 5, name: 'Grandchild #1' },
{ id: 6, name: 'Grandchild #2' },
],
},
],
},
];
},
methods: {
clickTest(array) {
const topLevel = 0;
const treeNodes = [];
array.forEach((item) => {
if (item.treeDepth === topLevel) {
const node = {};
node.id = item.id;
node.name = item.name;
node.children = this.makeNode(array, topLevel + 1, item.id);
treeNodes.push(node);
}
});
console.log(`${JSON.stringify(treeNodes)}`);
return treeNodes;
},
makeNode(array, level, parentId) {
const childNodes = [];
array.forEach((item) => {
if (item.treeDepth === level && item.parentId === parentId) {
const node = {};
node.id = item.id;
node.name = item.name;
node.children = this.makeNode(array, level + 1, item.id);
childNodes.push(node);
}
});
return childNodes;
},
checkAll() {
this.selection = [1];
console.log(this.selection);
},
customCheck(arr) {
this.selection = arr;
console.log(this.selection);
},
uncheckAll() {
this.selection = [];
},
changeCheck() {
console.log(this.selection);
this.selection[0] = 3;
this.selection.push();
this.$set(this.selection, 0, 4);
console.log(this.selection[0]);
},
},
};
검색방향을 달리하여 트리 노드 생성하는 함수를 찾아보았더니 많이 나오더라…..
좀 더 검색을 했더라면 더 빨리 처리했을 텐데…
팀장님 보기가 민망하다.