ASP.NET WebForm에서 jQuery treetable 플러그인을 활용한 계층형 테이블 관리

treetable 공식 사이트: http://ludo.cubicphuse.nl/jquery-treetable/#api

이번 작업은 테이블 기반 트리 노드를 표시하고 편집 및 삭제 기능을 구현하는 것이었습니다. 여러 레퍼런스를 참고하여 완성했습니다.

웹 서비스 구성

노드 검색 기능이 필요하므로, 하위 노드를 조회할 때 상위 노드 데이터도 함께 반환되도록 SQL을 구성했습니다:

sql.Append("select * from(");
sql.Append(@"SELECT
    row_number() OVER (ORDER BY CAST(a.SHOWINDEX AS NUMERIC(18,0)) ASC) AS rn,
    a.LAID,
    a.LABEL,
    b.LABEL AS parent,
    a.BELONINGLABLE,
    a.SHOWINDEX
FROM TB_LABEL a
LEFT JOIN TB_LABEL b ON b.LAID = a.BELONINGLABLE
WHERE (
    a.LABEL LIKE @bqm
    OR (
        SELECT COUNT(1) FROM TB_LABEL c
        WHERE c.BELONINGLABLE = a.LAID AND c.LABEL LIKE @bqm
    ) > 0
)");
sql.Append(") t WHERE rn BETWEEN @rn1 AND @rn2");

서버 측 데이터 정렬 (부모-자식 계층 순)

조회된 List 데이터를 부모 노드가 앞에 오도록 재정렬합니다:

using System.Collections.Generic;
using System.Linq;

namespace Web
{
    public static class TreeNodeHelper
    {
        public static List<LabelModel> SortedResult = new List<LabelModel>();
        private static List<LabelModel> _sourceNodes;

        public static List<LabelModel> BuildTreeList(List<LabelModel> flatList)
        {
            SortedResult.Clear();
            _sourceNodes = flatList;

            foreach (var node in _sourceNodes)
            {
                if (string.IsNullOrEmpty(node.ParentId))
                {
                    SortedResult.Add(node);
                    AppendChildren(node);
                }
            }
            return SortedResult;
        }

        private static void AppendChildren(LabelModel parent)
        {
            var children = GetChildNodes(parent);
            foreach (var child in children)
            {
                SortedResult.Add(child);
                AppendChildren(child);
            }
        }

        private static List<LabelModel> GetChildNodes(LabelModel parent)
        {
            return _sourceNodes
                .Where(n => n.ParentId == parent.Id)
                .ToList();
        }
    }

    public class LabelModel
    {
        public string Id { get; set; }
        public string ParentId { get; set; }
        public string Name { get; set; }
        public string DisplayIndex { get; set; }
    }
}

클라이언트 측 데이터 수신 및 테이블 생성

$.ajax({
    url: WebService + "/QueryLabelData",
    type: "POST",
    dataType: "json",
    data: '{keyword:"' + keyword + '"}',
    contentType: "application/json; charset=utf-8",
    success: function (response) {
        var data = JSON.parse(response.d);
        var rows = data.rows;
        var html = '<tbody><tr><td>이름</td><td>순서</td><td>작업</td></tr>';

        for (var i = 0; i < rows.length; i++) {
            var item = rows[i];
            var parentAttr = item.parentId ? ' data-tt-parent-id="' + item.parentId + '"' : '';
            html += '<tr data-tt-id="' + item.id + '"' + parentAttr + '>' +
                    '<td>' + item.name + '</td>' +
                    '<td>' + item.displayIndex + '</td>' +
                    '<td>' +
                        '<a class="btn" onclick="editNode(\'' + item.id + '\')">수정</a>' +
                        '<a class="btn" onclick="deleteNode(\'' + item.id + '\')">삭제</a>' +
                    '</td></tr>';
        }
        html += '</tbody>';
        $('#treeTableContainer').empty().append(html);
        loadTreeResources();
    }
});

테이블을 트리 형태로 변환 (리소스 동적 로딩)

var resourceLoadCount = 0;

function loadTreeResources() {
    // 이전에 로드된 treetable 관련 리소스 제거
    $("link[href*='treetable']").remove();
    $("script[src*='treetable']").remove();

    resourceLoadCount = 0;
    injectResource("css/treetable/jquery.treetable.css", "css");
    injectResource("css/treetable/jquery.treetable.theme.default.css", "css");
    injectResource("js/treetable/jquery.treetable.js", "js");
}

function injectResource(filePath, type) {
    var element;
    if (type === "js") {
        element = document.createElement('script');
        element.src = filePath;
    } else {
        element = document.createElement('link');
        element.rel = "stylesheet";
        element.href = filePath;
    }
    element.onload = function() {
        resourceLoadCount++;
        if (resourceLoadCount === 3) {
            // 이전 treetable 인스턴스 제거 후 새로 생성
            $('#treeTableContainer').treetable('destroy');
            $('#treeTableContainer').treetable({ expandable: true });
        }
    };
    document.head.appendChild(element);
}

핵심 포인트: 검색 시 테이블을 다시 렌더링해야 하므로, $('#treeTableContainer').treetable('destroy')로 이전 인스턴스를 제거한 후 새로운 데이터로 초기화해야 합니다.

참고 자료:

태그: jQuery treetable ASP.NET WebForm 트리테이블

6월 22일 20:00에 게시됨