如何在使用嵌套对象时在AngularJS中制作recursion模板?

我试图从一个JSON对象dynamic地构build一个表单,该对象包含表单元素的嵌套组:

$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"]} ]}, ]; 

我一直在使用ng开关块,但嵌套的项目变得站不住脚了,就像上面的Address对象一样。

这是小提琴: http : //jsfiddle.net/hairgamiMaster/dZ4Rg/

任何想法如何最好地处理这个嵌套问题? 非常感谢!

我认为这可以帮助你。 这是从我在Google小组发现的关于树中recursion元素的答案中得来的。

build议来自Brendan 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> 

所提出的解决scheme是关于如果当前元素具有子元素,则使用使用ng-include指令来调用自身的模板。

在你的情况下,我会尝试创build一个带有ng-switch指令的模板(每种types的标签都有一个例子),如果有任何子标签,在最后添加ng-include。

结合@jpmorin和@Ketan的build议(@ jpmorin的答案略有变化,因为它实际上并不工作)…有一个ng-if防止“叶儿”产生不必要的ng-repeat指令:

 <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> 

这里是Plunker的工作版本

可能会考虑使用ng-switch来检查Fields属性的可用性。 如果是这样,那么使用不同的模板。 这个模板在Fields数组上会有一个ng-repeat。

我知道这是一个古老的问题,但对于其他可能通过search来到这里的人来说,虽然我会留下一个解决scheme,对我来说更加整洁。

它build立在相同的想法,而不是必须存储模板内的模板caching等。我希望有一个更“干净”的解决scheme,所以我最终创build了https://github.com/dotJEM/angular-tree

使用相当简单:

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

由于该指令使用了transclusion而不是compile(截至最新版本),所以这应该比ng-include示例更好。

基于数据的例子在这里:

 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> 

只要在基于财产的结构的情况下扩展jpmorin post:

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

正如你可以看到这里的json对象不包含数组结构。

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> 

但是你可以迭代它。

在这里 ng-repeat属性的Angular文档

还有一些行的实现在这里