【问题标题】:Angularjs: Callback to parent controllerAngularjs:回调父控制器
【发布时间】:2015-09-30 05:41:14
【问题描述】:

请考虑以下代码:它有一个指令myItem 与隔离范围。每个项目将显示一个按钮,该按钮将在指令控制器上调用delete()。我希望这能在外部控制器 (AppController) 中触发 refresh。但是当然找不到refresh() 函数,因为作用域是孤立的。

   <html>
    <body ng-app="question">
        <div ng-cloak ng-controller="AppController">
            <my-item ng-repeat="item in list" data="list">
            </my-item>
            <input type="text" maxlength="50" ng-model="new_item" />
            <button ng-click="add(new_item)">+</button>
        </div>
        <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
        <script>
         (function () {
             var app;

             app = angular.module('question', []);


             app.controller('AppController', [
                 '$scope', '$http', function ($scope, $http) {
                     $scope.list = [];

                     function refresh(){
                         $http.get('/api/items').then(
                             function(response){
                                 $scope.list = response.data;
                             }
                         );
                     }

                     $scope.add = function(item){
                         $http.post('/api/items', { item: item }).then(refresh);
                     };

                     refresh();
                 }
             ]);

             app.directive('myItem', function() {
                 return {
                     scope: {
                         item: '=data',
                     },
                     // directive template with delete button
                     template: '{{ item }} <button ng-click="delete(item)">-</button>',
                     restrict: 'E',
                     // directive controller with delete function
                     controller: [ '$scope', '$http', function($scope, $http) {
                         $scope.delete = function (card) {

// This is where it goes wrong! refresh does not exist
                             $http.delete('/api/items' + card.id).then(refresh);
                         }
                     }]
                 };
             });
         })();
        </script>
    </body>
</html>

我可以做的一件事是在 myItem 指令中添加 ng-change,但这会涉及到需要 ngModelController,这似乎有点过头了。

我能想到的其他事情:

  1. 在指令的scope 属性中添加类似onchange: '@' 的内容,然后在html 中设置onchange = refresh。在 delete 函数内调用 onchange 表达式而不是刷新。但这感觉就像我在重新实现ng-change

  2. require: '^AppController' 添加到指令中。然后我想我可以直接在父控制器上调用refresh。这似乎违反了松散耦合。

  3. 根本不要使用隔离作用域。这意味着我们从父作用域继承并且refresh 可用。但随后我的指令隐含地假定范围将包含item。这也违反了松散耦合,但是以隐含的方式。

所以我的问题是:让父控制器知道它应该刷新其内容的正确方法是什么?

【问题讨论】:

  • 使用$rootScope怎么样?
  • @iam-decoder:我不知道$rootScope 并且无法快速找到很多有用的文档。对我有什么帮助?
  • 这个逻辑似乎是倒着实现的。您想向delete 发出服务器调用,然后立即告诉父控制器它应该向服务器发出get 调用以确定该项目真的被删除了吗?有很多方法可以在不涉及两个单独的服务器调用的情况下处理删除项目......
  • 事实上,在这种情况下,该指令根本不应该负责删除该项目。
  • 替代方案包括使用服务来维护数据的状态,或使用$broadcast 允许应用程序的其他区域响应更改。一般来说,最好尽可能限制与服务器通信的组件。

标签: javascript angularjs


【解决方案1】:

IMO,第一种方法是最好的方法。该指令从外部接收一个函数回调,必要时由该指令执行。像这样,这两个指令松散耦合。它类似于 ng-change 是 ng-model 指令使用的属性。

示例:指令

app.directive('myItem', function() {
    return {
        restrict: 'E',
        scope: {
            item: '=data',
            myItemDeleteCallback: '&myItemDeleteCallback'
        },
        template: '{{ item }} <button ng-click="delete(item)">-</button>',
        controller: [ '$scope', '$http', function($scope, $http) {
            $scope.delete = function (card) {
                // This is where it goes wrong! refresh does not exist
                $http.delete('/api/items' + card.id).then(function () {
                    $scope.myItemDeleteCallback();
                });
            }
        }]
    };
});

用途:控制器

app.controller('AppController', ['$scope', '$http', function ($scope, $http) {
    $scope.list = [];

    $scope.refresh = function (){
        $http.get('/api/items').then(
            function(response){
                $scope.list = response.data;
            }
        );
    };

    $scope.add = function(item){
        $http.post('/api/items', { item: item })
            .then($scope.refresh);
    };

    refresh();
}]);

用法:模板

<div ng-cloak ng-controller="AppController">
    <my-item my-item-delete-callback="refresh()" ng-repeat="item in list" data="list">
    </my-item>
    <input type="text" maxlength="50" ng-model="new_item" />
    <button ng-click="add(new_item)">+</button>
</div>

【讨论】:

  • 谢谢!只是想知道,不应该是$scope.myItemDeleteCallback()(前面加了美元符号)吗?
  • 是的,很抱歉错字并感谢您注意到它。已经修好了。
  • 接受这个作为正确答案。尽管@Claies 在上面的讨论中提出了一个有效的观点,但在我的情况下,他/她的推理是一个称为过早优化的陷阱的经典示例 :) 换句话说:在执行额外的 GET 时保持我的代码简单干净对我来说很好.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-15
  • 2018-01-03
  • 2023-03-10
  • 2019-04-01
相关资源
最近更新 更多