71

我正在尝试从 JSON 对象动态构建表单,该对象包含嵌套的表单元素组:

  $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-switch 块,但是对于嵌套项,它变得站不住脚,就像上面的 Address 对象一样。

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

关于如何最好地解决这个嵌套问题的任何想法?非常感谢!

4

5 回答 5

123

我认为这可以帮助你。它来自我在Google Group上找到的关于树中递归元素的答案。

建议来自 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>

建议的解决方案是使用模板,如果当前元素有子元素,则该模板使用 ng-include 指令调用自身。

在您的情况下,我会尝试使用 ng-switch 指令创建一个模板(就像您所做的那样,每种标签类型一个案例),如果有任何子标签,则在末尾添加 ng-include 。

于 2013-03-27T15:59:11.377 回答
10

结合@jpmorin 和@Ketan 的建议(@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的工作版本

于 2014-05-11T18:23:15.340 回答
1

可能会考虑使用 ng-switch 来检查 Fields 属性的可用性。如果是这样,则针对该条件使用不同的模板。此模板将在 Fields 数组上有一个 ng-repeat。

于 2013-03-27T14:43:46.650 回答
1

我知道这是一个老问题,但对于可能通过搜索来到这里的其他人,我虽然会留下一个对我来说更简洁的解决方案。

它建立在相同的想法上,但不必将模板存储在模板缓存等中。我希望有一个更“干净”的解决方案,所以我最终创建了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>

由于该指令使用嵌入而不是编译(从最新版本开始),因此它应该比 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>

于 2014-06-22T09:52:12.933 回答
0

如果是基于属性的结构,我只想扩展 jpmorin 帖子。

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 over properties here的Angular文档,

并且可以在此处找到一些行实现。

于 2014-09-03T09:27:41.953 回答