2013-08-28 28 views
0

我对AngularJS非常陌生,在观看一些复合视频后,我决定使用它创建一个简单的网页。与父亲儿童组合的动态表单

页面最初应该加载一个由ajax请求(包含所有数据)填充的选择框。然后,根据所选的值,可能需要创建一个包含子数据的新选择元素。这将继续发生,直到选择没有孩子ID的选项。我从api获取的数据格式如下。

[ { "ChildIds" : [ ], 
    "Id" : "1", 
    "Name" : "Top Level", 
    "ParentId" : null 
    }, 
    { "ChildIds" : [ "51" ], 
    "Id" : "22", 
    "Name" : "LevelA - 1", 
    "ParentId" : "1" 
    }, 
    { "ChildIds" : [ "38", 
     "26" 
     ], 
    "Id" : "24", 
    "Name" : "LevelA - 2", 
    "ParentId" : "1" 
    }, 
    { "ChildIds" : [ ], 
    "Id" : "38", 
    "Name" : "LevelB - 1", 
    "ParentId" : "24" 
    }, 
    { "ChildIds" : [ ], 
    "Id" : "26", 
    "Name" : "LevelB - 2", 
    "ParentId" : "24" 
    }, 
    { "ChildIds" : [ ], 
    "Id" : "51", 
    "Name" : "LevelB - 3", 
    "ParentId" : "22" 
    }, 
    { "ChildIds" : [ "43", 
     "21" 
     ], 
    "Id" : "36", 
    "Name" : "LevelC - 1", 
    "ParentId" : "26" 
    }, 
    { "ChildIds" : [ ], 
    "Id" : "43", 
    "Name" : "LevelD - 1", 
    "ParentId" : "36" 
    }, 
    { "ChildIds" : [ ], 
    "Id" : "21", 
    "Name" : "LevelD -2", 
    "ParentId" : "36" 
    } 
] 

我设法用硬编码选择元素得到这个工作,但要使这个充满活力。

的Html

<div class="container"> 
     <div ng-controller="organisationalUnitCtrl"> 
      <select class="form-control" ng-model="root" ng-options="ou.Name for ou in ous | filter:{ParentId:'!'}"> 
       <option value="">-- choose organisation unit --</option> 
      </select> 
      <select class="form-control" ng-model="child" ng-options="ou.Name for ou in ous | filter:{ParentId:root.Id}"> 
       <option value="">-- choose organisation unit --</option> 
      </select> 
      <select class="form-control" ng-model="child2" ng-options="ou.Name for ou in ous | filter:{ParentId:child.Id}"> 
       <option value="">-- choose organisation unit --</option> 
      </select> 
      <select class="form-control" ng-model="child3" ng-options="ou.Name for ou in ous | filter:{ParentId:child2.Id}"> 
       <option value="">-- choose organisation unit --</option> 
      </select> 
     </div> 
    </div> 

控制器

bristowRiskApp.controller('organisationalUnitCtrl', 
    function organisationalUnitCtrl($scope, organisationalUnitData) { 
     $scope.ous = organisationalUnitData.getOrganisationalUnit(); 
    } 
); 

服务

bristowRiskApp.factory('organisationalUnitData', function ($http, $q) { 
    return { 
     getOrganisationalUnit: function() { 
      var deferred = $q.defer(); 

      $http({ method: 'GET', url: 'http://localhost:53995/api/organisationalunit' }). 
       success(function (data, status, headers, config) { 
        deferred.resolve(data); 
       }). 
       error(function (data, status, headers, config) { 
        deferred.reject(status); 
       }); 

      return deferred.promise; 
     } 
    } 
}); 

我已阅读,你应该不是人在控制器中使用DOM。所以,我猜测我应该为我的select元素创建一个指令来监听onChange事件并创建新的select元素?我该怎么做呢?我能从中学到什么样的例子吗?

我在硬编码示例中遇到的另一个问题是,更改select中的值只会涟漪到下一个组合。例如,如果在所有四个选择框中选择了值,则更改第二个框中的值将正确地重置第三个框,但第四个框仍将包含所选的选项。我认为这种变化会一路波澜起伏。

感谢

史蒂芬

+0

是的,你需要一个指令。实际上,我之前写过一个懒惰装载的树 - 但它是我公司的财产,因为我在他们的硬币上做了它,所以我不能只提供源代码。如果您阅读有关指令并回答具体问题,我可以提供帮助。虽然可能不是最有效的方式,你可能需要请求'$ compile'服务并在''link''函数中使用它。我通过google了解了指令和角度(还有很多SO),试验和错误。我不知道有一个专门了解指令的好地方。 –

+0

了解:指令,隔离范围,'=','&','@'用于在隔离范围内进行通信,'$ compile'服务,'angular.element'用于创建递归元素,使用'link'属性指令。这可能是你需要的一切。另一个建议的话:让这个可重用的指令接受'&'为了点击什么和在哪里获得文本显示(与硬编码'.text'属性访问器相反)。 –

+1

谢谢Jared。我最近没有太多时间来研究它,但研究了隔离范围和与我的指令沟通的方法。 我已经设法至少使用指令创建组合,并传递必要的参数。我只是没有得到的部分是在哪里捕捉组合中的变化。我创建了一个可以触发的element.on方法。但是,我似乎无法访问我需要的数据。我已经创建了一个基于我迄今为止所做的小提琴。正确的方向? http://jsfiddle.net/stevendwebster/E5ss4/7/ –

回答

1

让我知道如果/为什么这不工作,我会相应地解决它。我认为关键的事实是在选项中继器中,您没有使用语法来指定选项的ID - 您只是在做它的标签。

http://jsfiddle.net/KVdqb/

HTML

<div ng-app="bristowRiskApp" ng-controller="organisationalUnitCtrl"> 
    $scope.selections: <pre>{{ selections | json }}</pre> 
    <div ng-repeat="i in range(selections.length - 1)"> 
     <cascade-select data="data" parent-id="selections[i]" selected-id="selections[i + 1]"></cascade-select> 
    </div> 
</div> 

的Javascript

var bristowRiskApp = angular.module('bristowRiskApp', []); 

bristowRiskApp.controller('organisationalUnitCtrl', 

function organisationalUnitCtrl($scope) { 
    $scope.data = [ /* ... */ ]; 

    $scope.selections = [ null, null ]; 

    $scope.$watch('selections', function (value) { 
     if (value[value.length - 1] !== null || value.length < 2) { 
      value.push(null); 
     } else { 
      var index = value.indexOf(null, 1); 
      if (0 < index && index < value.length - 1) { 
       $scope.selections = value.slice(0, index); 
      } 
     } 

    }, true); 

    // Helper function.  
    $scope.range = function (n) { 
     var result = []; 

     for (var i = 0 ; i <n; i++) { 
      result.push(i); 
     } 

     return result; 
    }; 
}); 

bristowRiskApp.directive('cascadeSelect', function() { 
    return { 
     restrict: 'E', 
     replace: true, 
     scope: { 
      parentId: '&', 
      selectedId: '=', 
      data: '=' 
     }, 
     template: '<select ng-show="(data | filter:byId).length > 0" ng-model="selectedId" ng-options="d.Id as d.Name for d in data | filter:byId"><option value="">-- choose organisation unit --</option></select>', 
     link: function (scope, element, attrs) { 
      scope.byId = function (d) { 
       return d.ParentId === scope.parentId(); 
      }; 
     } 
    } 
}); 
+1

非常感谢Jared。这正是我正在寻找的,我找不到任何问题。我想更仔细地研究你的代码,并尝试学习你所使用的技术。 –

+0

:)让我知道你是否有任何东西会让你痛苦。 –

+0

嗨Jared,“byId”函数难倒了我一段时间,但后来在文档中阅读,你可以传递一个函数作为比较器。我确实需要添加的一件事是处理更高级别的组合的代码。例如,如果4个组合有值,我改变了第2个,它将清除第3个和awaute选择,但是第4个不会被删除。 –