【问题标题】:supplying AngularJS controller data提供 AngularJS 控制器数据
【发布时间】:2013-12-04 03:41:26
【问题描述】:

假设有一个控制器来处理示波器上的一些数据,那么向控制器提供这些数据的最佳做法是什么?

例如,如果我有一个项目列表,我可能想要一个 ListController 来操纵列表,并希望一个 ItemController 来操纵单个项目。但是我如何给每个 ItemController 一个项目来使用呢?

在下面的情况下,doSomethingToItem 将如何访问该项目。当嵌套在 ngRepeat 中时,项目是 $scope.item,但在选择视图中,我们要操作的项目是 $scope.selection。

angular.module('MyApp', [])

    .controller('ListController', function($scope, $http) {

        $scope.list = $http.get(...);

        $scope.selection = null;

    })

    .controller('ItemController', function($scope) {

        $scope.doSomethingToItem = function() {
            ...
        };

    })


<div ng-controller="ListController">
    <div ng-repeat="item in list" ng-click="selection = item">
        <div ng-controller="ItemController">
            <button ng-click="doSomethingToItem()">Do Something</button>
        </div>
    </div>
    <div ng-show="selection"
        <div ng-controller="ItemController">
            <button ng-click="doSomethingToItem()">Do Something</button>
        </div>
    </div>
</div>

这不是一个常见的结构,还是我的想法倒退了?

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    您应该了解 Angular 会在您的情况下创建 n+1 个 ItemController。 N 代表项目,1 代表选择部分。

    为了使传递需要处理的对象更容易,您可以将方法签名更改为

    doSomethingToItem(item) 和在 html 中做

    &lt;button ng-click="doSomethingToItem(item)"&gt;Do Something&lt;/button&gt; 在两个地方。

    否则对于重复情况,item 变量包含您可以在 ItemController 中访问的对象

    selection 变量包含对选择控制器的引用,可以从选择部分下定义的控制器实例中引用。

    更新:ng-repeat 和 selection 中的表达式会有所不同

    &lt;button ng-click="doSomethingToItem(item)"&gt;Do Something&lt;/button&gt;

     <div ng-show="selection"
            <div ng-controller="ItemController">
                <button ng-click="doSomethingToItem(selection)">Do Something</button>
            </div>
        </div>
    

    【讨论】:

    • 我认为这也行不通?当您在模板中使用变量时,它会绑定到 $scope。因此,我希望 doSomethingToItem(item) 尝试在 ItemController 中解析 $scope.item。那将是未定义的。
    • 将 item 传递给 doSomethingToItem() 是个好主意,但你会损失很多。此时,您不妨将函数放在 ListController 上,以避免像您指出的那样运行 ItemController N+1 次。您使用 ItemController 的原因是获取该范围,以便您可以执行 $scope.$on('some-event', function() { ... });$scope.$watch('expression', function() { ... }); 之类的操作,这些回调如何知道该项目是什么?
    • 对于事件来说,这将是不关注的问题。事件需要传入它正在处理的数据对象。
    【解决方案2】:

    您可以像这样传递项目数据模型:

    <div ng-init="instance = item" ng-controller="ItemController">
    </div>
    

    “instance”将引用“ListController”中的列表数组数据模型项。

    你可以在你的 ItemController 函数闭包中访问它的属性:

    .controller("ItemController", function($scope){
      $scope.instance={};
      $scope.doSomething = function(){
        console.log($scope.instance.name);
      }
      $scope.$watch('instance',function(){
        console.log("iitem changed");
      },true);
    });
    

    我不太确定您希望在“选择”实现中实现什么功能。

    我认为你想实现一个选定的列表,当用户单击列表项时,列表项将被添加到其中。如果您想将所选项目添加到列表中,您可以尝试创建一个“选定列表”模型来控制所选列表视图。

    ListController.js

    .controller("ListController", function($scope){
      $scope.selectedList = [];
      $scope.addItem = function(item){
        $scope.selectedList.push(item);
      }
    });
    

    HTML

    <div ng-repeat="selected in selectedList">
      <div ng-init="instance = selected" ng-controller="ItemController">
        <span>{{instance.name}}</span>
        <button ng-click="doSomething()">selectedAction</button>
      </div>
    </div>
    

    我写了一个简单的多选列表示例如下:

    HTML

    <!doctype html>
    <html lang="en" ng-app="myApp">
    <head>
    <meta charset="UTF-8">
    <title>Nested controller</title>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
    <script src="js/nestedController.js"></script>
    </head>
    <body>
    <div ng-controller="parentCtrl">
        <h2>List</h2>
        <div ng-repeat="item in list">
            <input type="checkbox" ng-model="item.selected" ng-checked="item.selected"/>
            <div ng-init="instance = item" ng-controller="childCtrl">
                <span>{{instance.name}}</span>
                <button ng-click="doSomething()">doSomething</button>
            </div>          
        </div>
        <h2>Selected</h2>
        <div ng-repeat="selected in selectedList">
            <div ng-init="instance = selected" ng-controller="childCtrl">
                <span>{{instance.name}}</span>
                <button ng-click="selectedAction()">selectedAction</button>
            </div>
        </div>
    </div>
    

    JS

    angular.module("myApp",[])
    .controller("parentCtrl",function($scope){
      //test data
      $scope.list = [{name:'item1',age:'12',selected:false},{name:'item2',age:'18',selected:false}];
      //use model to control selected list view
      $scope.selectedList = [];
      //refresh the selected list model when the list checked stauts has been updated
      $scope.$watch('list',function(){
        console.log("parent controller detected change");
        $scope.selectedList = [];
        $scope.list.forEach(function(elem,index,array){
            if(elem.selected===true){
                $scope.selectedList.push(elem);
            }
        });
      },true);
    })
    .controller("childCtrl",function($scope){
      $scope.instance={}
      $scope.doSomething = function(){
        alert("I'm the item: "+$scope.instance.name);
      }
    
      $scope.selectedAction = function(){
        alert("I'm the selected item: "+$scope.instance.name);
      }
      //could register a watcher to monitor the model status
      $scope.$watch('instance',function(){
        console.log("child controller detected change");
      },true);
    });
    

    这里是jsFiddle demo

    希望这会有所帮助。

    【讨论】:

    • 这是个好主意。谢谢。由于 angularjs 文档中的这一行,我犹豫是否使用 ngInit:“ngInit 用于别名 ngRepeat 的特殊属性的唯一适当用途,如下面的演示所示。除了这种情况,您应该使用控制器而不是 ngInit 来初始化值一个范围。”他们将它用于嵌套 ngRepeats 的地方:ng-repeat="innerList in list" ng-init="outerIndex = $index"。尽管他们没有解释为什么发表此评论。
    猜你喜欢
    • 1970-01-01
    • 2017-09-02
    • 2015-06-23
    • 1970-01-01
    • 2018-09-29
    • 2017-05-03
    • 2016-05-28
    • 2017-10-23
    • 1970-01-01
    相关资源
    最近更新 更多