2015-09-29 5 views
0

Пожалуйста, обратите внимание на следующий код: он имеет директиву myItem с областью выделения. На каждом элементе отображается кнопка, которая будет вызывать delete() на контроллере. Я бы хотел, чтобы это вызвало refresh во внешнем контроллере (AppController). Но, конечно, функция refresh() не может быть найдена из-за изолированного объема.Angularjs: Обратный звонок к родительскому контроллеру

<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, но это предполагает требующий ngModelController, который кажется излишним.

Другие вещи, которые я могу думать:

  1. Добавить что-то вроде onchange: '@' атрибуту директивы scope, а затем установить onchange = refresh в HTML. Вызовите выражение onchange вместо обновления внутри функции delete. Но похоже, что я переустанавливаю ng-change?

  2. Добавить require: '^AppController' в указатель. Тогда, я думаю, я мог бы позвонить refresh на родительский контроллер напрямую. Кажется, что это нарушает свободную связь.

  3. Не используйте область изоляции вообще. Это означало бы, что мы наследуем родительскую область и доступно refresh. Но тогда моя директива неявно предполагает, что область будет содержать item. Который также нарушает свободную связь, но неявным образом.

Итак, мой вопрос: что является правильным способом сообщить родительскому контроллеру, что он должен обновить его содержимое?

+0

насчет использования '$ rootScope'? –

+0

@ iam-decoder: я не знаю «$ rootScope» и не могу быстро найти много полезной документации. Как это мне поможет? – rje

+1

эта логика, похоже, в любом случае реализована в обратном направлении. Вы хотите выдать вызов сервера 'delete', а затем сразу сообщить родительскому контроллеру, что он должен сделать вызов' get' на сервер, чтобы выяснить, что элемент действительно удален? Существует множество способов обращения с удалением элемента без использования двух отдельных вызовов сервера .... – Claies

ответ

2

ИМО, первым способом был бы лучший способ. Директива получает обратный вызов функции извне, который при необходимости выполняется директивой. Подобным образом две директивы слабо связаны. Он похож на 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> 
+0

Спасибо! Просто интересно, разве это не '$ scope.myItemDeleteCallback()' (знак доллара добавлен спереди)? – rje

+0

Да, извините за опечатку и спасибо, что заметили это. Это уже исправлено. –

+0

Принимая это как правильный ответ. Хотя @Claies делает верную точку в обсуждении выше, в моем случае его аргументация является классическим примером ловушки под названием «Преждевременная оптимизация». Другими словами: сохранение моего кода простым и чистым при выполнении дополнительного GET в порядке со мной , – rje

Смежные вопросы