2013-03-27 13 views
70

Próbuję zbudować formę dynamicznie z obiektu JSON, który zawiera grupy zagnieżdżonych elementów forma:Jak utworzyć rekursywne szablony w AngularJS przy użyciu obiektów zagnieżdżonych?

$scope.formData = [ 
    {label:'First Name', type:'text', required:'true'}, 
    {label:'Last Name', type:'text', required:'true'}, 
    {label:'Coffee Preference', type:'dropdown', options: ["HiTest", "Dunkin", "Decaf"]}, 
    {label: 'Address', type:'group', "Fields":[ 
     {label:'Street1', type:'text', required:'true'}, 
     {label:'Street2', type:'text', required:'true'}, 
     {label:'State', type:'dropdown', options: ["California", "New York", "Florida"]} 
    ]}, 
    ]; 

Używam bloki ng-switch, ale staje się nie do utrzymania z zagnieżdżonych elementów, jak w powyższym obiekcie Adres.

Oto skrzypce: http://jsfiddle.net/hairgamiMaster/dZ4Rg/

Wszelkie pomysły, w jaki sposób najlepiej podejść do tego problemu zagnieżdżony? Wielkie dzięki!

+0

po prostu odpowiedział na to w dość ogólny sposób na na innym pytaniem: http://stackoverflow.com/questions/ 14430655/rekursja w kanciastych dyrektywach/29736154 # 29736154 – tilgovi

Odpowiedz

117

Myślę, że to może ci pomóc. Jest to odpowiedź znaleziona na Google Group o rekurencyjnych elementach w drzewie.

Sugestia jest z Brendanem Owen: http://jsfiddle.net/brendanowen/uXbn6/8/

<script type="text/ng-template" id="field_renderer.html"> 
    {{data.label}} 
    <ul> 
     <li ng-repeat="field in data.fields" ng-include="'field_renderer.html'"></li> 
    </ul> 
</script> 

<ul ng-controller="NestedFormCtrl"> 
    <li ng-repeat="field in formData" ng-include="'field_renderer.html'"></li> 
</ul> 

Proponowane rozwiązanie jest o użyciu szablonu, który używa ng obejmują dyrektywę nazywać się jeśli bieżący element ma dzieci.

W twoim przypadku chciałbym utworzyć szablon z dyrektywą ng-switch (jeden przypadek na każdy typ etykiety, tak jak zrobiłeś) i dodać Ng-include na końcu, jeśli są tam etykiety podrzędne.

+2

Wielkie dzięki - myślę, że jest to technika, której należy użyć. Twoje zdrowie! –

+0

co, jeśli struktura danych się nie powtórzy, więc nie można użyć wzmacniaka, ale masz nieokreśloną liczbę zagnieżdżonych wartości? Zobacz: http://stackoverflow.com/questions/25044253/how-can-you-navigate-a-tree-in-reverse-order-with-angularjs – Randyaa

+0

Zobacz moją odpowiedź na pytanie: http://stackoverflow.com/a/25047327/1036025 – jpmorin

1

Może rozważyć użycie przełącznika Ng, aby sprawdzić dostępność właściwości pól. Jeśli tak, użyj innego szablonu dla tego warunku. Ten szablon miałby powtórzenie ng w tablicy Fields.

10

Łącząc co @jpmorin i @Ketan zasugerował (nieznaczne zmiany na odpowiedź użytkownika @ jpmorin ponieważ w rzeczywistości nie pracuje jak jest) ... Jest takie ng-if aby zapobiec „dzieci” z liści generowania niepotrzebnych ng-repeat dyrektyw:

<script type="text/ng-template" id="field_renderer.html"> 
    {{field.label}} 
    <ul ng-if="field.Fields"> 
     <li ng-repeat="field in field.Fields" 
     ng-include="'field_renderer.html'"> 
     </li> 
    </ul> 
</script> 
<ul> 
    <li ng-repeat="field in formData" ng-include="'field_renderer.html'"></li> 
</ul> 

oto wersja pracująca w Plunker

1

wiem, jest to stara sprawa, ale dla innych, którzy mogą przyjść przez tutaj chociaż wyszukiwania, ja jednak chciałbym zostawić rozwiązanie, które jest dla mnie nieco bardziej schludny.

Opiera się ona na tej samej idei, ale zamiast przechowywać szablonu wewnątrz szablonu cache itp Żałowałam dla bardziej rozwiązania „czysty”, więc skończyło się na tworzeniu https://github.com/dotJEM/angular-tree

jest dość prosty w obsłudze :

<ul dx-start-with="rootNode"> 
    <li ng-repeat="node in $dxPrior.nodes"> 
    {{ node.name }} 
    <ul dx-connect="node"/> 
    </li> 
</ul> 

Ponieważ dyrektywa wykorzystuje transkluzja zamiast kompilacji (w najnowszej wersji), to powinno działać lepiej niż ng obejmują np.

Przykład na podstawie danych tutaj:

angular 
 
    .module('demo', ['dotjem.angular.tree']) 
 
    .controller('AppController', function($window) { 
 

 
    this.formData = [ 
 
     { label: 'First Name', type: 'text', required: 'true' }, 
 
     { label: 'Last Name', type: 'text', required: 'true' }, 
 
     { label: 'Coffee Preference', type: 'dropdown', options: ["HiTest", "Dunkin", "Decaf"] }, 
 
     { label: 'Address', type: 'group', 
 
     "Fields": [{ 
 
     label: 'Street1', type: 'text', required: 'true' }, { 
 
     label: 'Street2', type: 'text', required: 'true' }, { 
 
     label: 'State', type: 'dropdown', options: ["California", "New York", "Florida"] 
 
     }] 
 
    }, ]; 
 

 
    this.addNode = function(parent) { 
 
     var name = $window.prompt("Node name: ", "node name here"); 
 
     parent.children = parent.children || []; 
 
     parent.children.push({ 
 
     name: name 
 
     }); 
 
    } 
 

 
    this.removeNode = function(parent, child) { 
 
     var index = parent.children.indexOf(child); 
 
     if (index > -1) { 
 
     parent.children.splice(index, 1); 
 
     } 
 
    } 
 

 
    });
<div ng-app="demo" ng-controller="AppController as app"> 
 

 
    <form> 
 
     <ul class="unstyled" dx-start-with="app.formData" > 
 
      <li ng-repeat="field in $dxPrior" data-ng-switch on="field.type"> 
 
       <div data-ng-switch-when="text"> 
 
        <label>{{field.label}}</label> 
 
        <input type="text"/> 
 
       </div> 
 
       <div data-ng-switch-when="dropdown"> 
 
        <label>{{field.label}}</label> 
 
        <select> 
 
         <option ng-repeat="option in field.options" value="{{option}}">{{option}}</option> 
 
        </select> 
 
       </div> 
 
       <div data-ng-switch-when="group" class="well"> 
 
        <h2>{{field.label}}</h2> 
 
        <ul class="unstyled" dx-connect="field.Fields" /> 
 
       </div> 
 
      </li> 
 
     </ul> 
 
      <input class="btn-primary" type="submit" value="Submit"/> 
 
    </form> 
 
    
 
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script> 
 
    <script src="https://rawgit.com/dotJEM/angular-tree-bower/master/dotjem-angular-tree.min.js"></script> 
 

 
</div>

0

prostu chcesz przedłużyć jpmorin słupek w przypadku nieruchomości w oparciu strukturze:

JSON: 
{ 
      "id": 203, 
      "question_text_id": 1, 
      "yes": { 
      "question_text_id": 25, 
      "yes": { 
       "question_text_id": 26 
      } 
      }, 
      "no": { 
      "question_text_id": 4 
      } 
     } 

Jak widać json obiektu tutaj nie zawiera struktury tablicowej.

HTML

<div> 
    <script type="text/ng-template" id="tree_item_renderer.html"> 
     <span>{{key}} {{value}}</span> 
     <ul> 
      <li ng-repeat="(key,value) in value.yes" ng-include="'tree_item_renderer.html'"></li> 
      <li ng-repeat="(key,value) in value.no" ng-include="'tree_item_renderer.html'"></li> 
     </ul> 
    </script> 

    <ul> 
     <li ng-repeat="(key,value) in symptomeItems" ng-include="'tree_item_renderer.html'"></li> 
    </ul> 
</div> 

Jednak można iteracyjne nad nim.

kątowa dokumentacja dla NG-repeat nad właściwościami here

a niektóre realizacji wiersz here

Powiązane problemy