2017-02-15 4 views
0

다중 열 트리 (트리 테이블 또는 트리 그리드)를 각도로 렌더링하려고합니다. 내 데이터는 임의의 깊이의 나무이며,이 같은 같습니다JSON 트리를 들여 쓴 테이블로 렌더링하는 AngularJS 지시문

[ 
    {name: "node 1", 
    type: "folder", 
    children: {[ 
       {name:"node 1-1", type:file}, 
       {name:"node 1-2", type:file}, 
       {name:"node 1-3", type:file}, 
       ]} 
    }, 
    ... 
    ... 
] 

나는 UL/리튬 트리에이를 렌더링하는 재귀 템플릿을 사용하는 예를 본 적이,하지만 나는 여러 열을 필요, 그래서 나는 생각한다 테이블이 필요해.

<tr> 
    <td> 
    node 1 
    </td> 
    <td> 
    folder 
    </td> 
</tr> 
<tr> 
    <td> 
    <span class="treetable-padding"/> 
    node 1-1 
    </td> 
    <td> 
    file 
    </td> 
</tr> 
... 
... 

그래서, 즉이 트리 깊이 범위의 요소 수를 사용하여 표현되는 단지 평평한 테이블이있다 : 지금까지 내가 함께 온 최고의 HTML은 같을 것입니다 위의 데이터 구조를 렌더링 그 숫자는 계층 구조의 해당 레벨과 같습니다.

일반적으로 html/AngularJS/js와 잘 맞지 않아 이것이 내 데이터를 렌더링하는 가장 좋은 방법인지는 잘 모르겠지만 원하는 방식대로 보입니다.

제 질문은 AngularJS를 사용하여 가장 좋은 방법은 무엇입니까? JavaScript에서 이와 같은 모 놀리 식 덩어리를 만들어서 맞춤형 지시어로 감쌀 수 있다는 것을 알고 있지만 데이터 바인딩 등을 활용할 수 있도록 Angular의 정신에서 더 많은 솔루션을 찾고 있습니다. 궁극적으로 세포를 편집 가능하게하여 데이터 바인딩을 지저분하게 만들려는 작업을하고 싶지는 않습니다.

"깊이"특성을 명시 적으로 포함하는 개체 목록에 내 트리를 병합하는 코드를 작성하려고 생각했습니다. 그렇다면 ng-repeat를 사용할 수 있습니다. 하지만 하나 이상의 맞춤 지정 문을 사용하는 더 깨끗한 방법이 있다고 생각했습니다.

고마워요!

+0

어떤 이유로 든이 테이블이 필요합니까? 편집을 허용하기 위해 [angular-json-tree] (https://github.com/awendland/angular-json-tree)와 같은 지시문을 확장 해 볼 수 있습니다. – haxxxton

+0

여러 열이 필요합니다. 나는 간략하게하기 위해 그들을 보여주지 않았다. –

+0

추가 열을 사용하여 달성하고자하는 목표는 무엇입니까? :) 편집/삭제/복제 버튼 : – haxxxton

답변

0

저는 지금 뭔가 효과가 있습니다. 위 질문에 대한 제 의견에 설명 된대로 작동합니다. 요컨대, ng-repeat를 기반으로하는 두 개의 사용자 정의 지시문을 사용하고 있습니다. 첫 번째는 깊이를 나타 내기 위해 class 속성에 리터럴 값이있는 플랫 테이블 구조를 만듭니다. 두 번째 지시문은 해당 심도 정보를 사용하여 적절한 횟수만큼 패딩 요소를 반복합니다. 두 repeater는 html에 대한 제한 사항/종속성을 최소화하기 위해 transclusion을 사용합니다. 유일한주의 사항은 두 번째 리피터가 깊이 정보를 필요로한다는 것입니다. 깊이 정보는 DOM 내의 조상입니다.

다음은 HTML 템플릿 내 질문에 설명 된 구조의 나무 테이블을 생성하는 모습입니다 :

<table class="treetable" style="width: 40%;"> 
    <tr class="treetable-node" my-repeat="item in things" 
    my-repeat-children="children"> 
<td> 
    <span my-repeat-padding class="treetable-node-indent"></span> 
    {{ item.name }} 
</td> 
<td> 
    {{ item.type }} 
</td> 
    </tr> 
</table> 

나는 this 예에 내 사용자 지정 중계기를 기반으로. 내 것이 다른 점은 "children"속성을 지정할 수 있고 지시문 논리가 각 항목의 해당 속성을 확인하고 거기에있는 경우 재귀 적으로 강등된다는 것입니다. 모든 새 요소를 동일한 부모에게 첨부하지만 나에게 플랫 구조.

아마도 매우 비효율적이며 일부 최적화를 사용할 수 있습니다. 링크의 코드와 같이 변경 사항이있을 때 모든 것을 다시 작성합니다.

myApp.directive("myRepeat", function($parse) { 
    return { 
    restrict: "A", 
    replace: true, 
    transclude: "element", 
    link: function (scope, element, attrs, controller, transclude) { 
     match = attrs.myRepeat.match(/^\s*(.+)\s+in\s+(.*?)\s*(\s+track\s+by\s+(.+)\s*)?$/); 
     itemName = match[1]; 
     collectionName = match[2]; 
     childCollectionName = attrs["myRepeatChildren"]; 
     parentElement = element.parent(); 
     elements = []; 

     scope.$watchCollection(collectionName, function(collection) { 
     var i, block, childScope; 
     if (elements.length > 0) { 
      for(i=0; i<elements.length; i++) { 
      elements[i].el.remove(); 
      elements[i].scope.$destroy(); 
      }; 
      elements = []; 
     } 

     var buildHtml = function(parent, itemList, depth=0) { 
      for (var i=0; i<itemList.length; i++) { 
      childScope = scope.$new(); 
      childScope[itemName] = itemList[i]; 

      transclude(childScope, function(clone) { 
       parentElement.append(clone); 
       block = {}; 
       block.el = clone; 
       block.scope = childScope; 
       block.el.addClass("depth-" + depth); 
       elements.push(block); 
      }); 

      /*Recurse if this item has children, 
       adding the sub-elements to the same 
       parent so we end up with a flat list*/ 
      if(childCollectionName in itemList[i]) { 
       buildHtml(parentElement, 
         itemList[i][childCollectionName], 
         depth+1); 
      } 

      } 
     } 
     for (i=0; i<collection.length; i++) { 
      buildHtml(parentElement, collection); 
     } 

     }); 
    } 
    }; 
}); 

두 번째 것은 약간 해킹입니다. 그것은 또한 transcluding 중계기입니다. 깊이 클래스 속성에 대해 DOM에서 위쪽으로 검색하고 깊이 값을 파싱 한 다음 여러 번 그 자체를 부모 앞에 추가합니다. 따라서 그것은 첫 번째 지시어에 의해 설정된 깊이 등급에 전적으로 의존합니다. 아마 그것을하는 더 좋은 방법이 있습니다. 이 시계는 순수하게 화장품이기 때문에 시계 등을 설치하는 것을 신경 쓰지 않았습니다.

myApp.directive("myRepeatPadding", function($parse) { 
    return { 
    restrict: "A", 
    replace: true, 
    transclude: "element", 
    terminal: true, 
    link: function (scope, element, attrs, controller, transclude) { 
     var getDepth = function(element) { 
     classes = element.attr("class"); 
     if (classes) { 
      match = classes.match(/depth-([\d+])/); 
      if(match.length > 0) { 
      return match[1]; 
      } else { 
      return getDepth(element.parent()); 
      } 
     } else { 
      return getDepth(element.parent()); 
     } 


     } 
     depth = getDepth(element); 
     for (var i=0; i<depth; i++) { 
     transclude(scope, function(clone) { 
      element.parent().prepend(clone); 
      block = {}; 
      block.el = clone; 
      block.scope = scope; 
      elements.push(block); 
     }); 
     } 
    } 
    }; 
}); 

완벽하지는 않지만 개선하는데 시간을 투자해야합니다. 나는 내가 제작하는 HTML이 내가 원하는 모습을 얻는 가장 좋은 방법인지는 모르겠다. 그러나 html 템플릿을 적당하게 보이게 유지하면서 원하는 방식으로 렌더링한다.