2015-02-27 2 views
7

Я создаю многоразовые компоненты пользовательского интерфейса с директивами AngularJS. Я хотел бы иметь контроллер, который содержит мою бизнес-логику с вложенными компонентами (директивами). Я хочу, чтобы директивы могли управлять одним свойством в области контроллера. Директивам необходимо обладать изоляцией, потому что я могу использовать одну и ту же директиву более одного раза, и каждый экземпляр должен быть привязан к определенному свойству области контроля.Обновление области контроллера по директиве

До сих пор единственным способом, с помощью которого я могу применить изменения к области управления, является вызов scope.$apply() из директивы. Но это прерывается, когда я нахожусь внутри обратного вызова ng-click из-за ошибок rootScope: inprog (незавершенная операция).

Я подумал о функции на контроллере, которую директива могла бы позвонить, чтобы сделать обновление, но это кажется тяжелым для меня.

Это мой код, который разбивается на обратный вызов ng-click. Имейте в виду, что я не просто хочу решить проблему с ng-click. Я хочу лучшее общее решение для применения директив многократного использования для изменения родительской области/модели.

HTML

<div ng-controller="myCtrl"> 
    <my-directive value="val1"></my-directive> 
</div> 

Контроллер

... 
.controller('myCtrl', ['$scope', function ($scope) { 
    $scope.val1 = 'something'; 
}}); 

директива

... 
.directive('myDirective', [function() { 

return { 
    link: function(scope) { 
     scope.buttonClick = function() { 
      var val = 'new value'; 
      scope.value = val; 
      scope.$apply(); 
     }; 
    }, 
    scope: { 
     value: '=' 
    }, 
    template: '<button ng-click="buttonClick()"></button>' 
}; 
}]); 
+0

Вы могли испускать события на $ rootScope. –

+0

@camden_kid Я надеялся на лучшее инкапсулирование. По крайней мере, я буду использовать метод контроллера, который я рассмотрел. Я не думаю, что хочу добавить больше болтовни на область корня, хотя. – Brett

+1

Вам не нужно вызывать $ apply(), так как функция buttonClick вызывается директивой ng-click и, таким образом, не выполняется вне обработки событий углов. Если вы хотите изменить атрибут, то у вас есть штраф (за исключением того, что вы не должны использовать $ apply()). Если вы хотите вызвать функцию обратного вызова, затем передайте вызываемую функцию с помощью '' & ''вместо'' = ''. –

ответ

4

Цель двухсторонней привязки данных в директории ectives - это именно то, о чем вы просите - для директив [allow] изменять родительскую область/модель ».

Сначала проверьте, правильно ли вы настроили двустороннюю привязку данных атрибута директивы, который предоставляет переменную, которую вы хотите разделить между областями. В контроллере вы можете использовать $watch для обнаружения обновлений, если вам нужно что-то сделать, когда значение изменится. Кроме того, у вас есть возможность добавить атрибут обработчика событий в директиву. Это позволяет директиве вызывать функцию, когда что-то происходит. Вот пример:

<div ng-controller="myCtrl"> 
    <my-directive value="val1" on-val-change="myFunc"> <!-- Added on-change binding --> 
     <button ng-click="buttonClick()"></button> 
    </my-directive> 
</div> 
+0

ты указал мне на правильный путь. Моя проблема была запутана с двухсторонними связями и примитивами. – Brett

4

Я думаю, что ваш вопрос о $scope.apply является отвлекающим маневром. Я не уверен, какая проблема была для вас решена, когда вы разработали эту демонстрацию и вопрос, но это не то, для чего это необходимо, и FWIW your example works for me without it.

Вы не должны беспокоиться об этой проблеме («заставить контроллер знать ... что [что-то] изменило значение в области»); Угловое связывание данных позаботится об этом автоматически.

Здесь немного сложно, потому что с директивой есть несколько областей, о которых можно беспокоиться. Внешняя область относится к <div ng-controller=myCtrl> и эта область имеет свойство .val, и есть внутренняя область, созданная <my-directive>, которая также имеет свойство .val, а обработчик внутри myDirective изменяет внутренний.Но вы объявили область myDirective с value: '=', которая устанавливает двунаправленную синхронизацию этого значения свойства между внутренней и внешней областью.

Поэтому он должен работать автоматически, и в плункере, который я создал из вашего кода вопроса, он работает автоматически.

Откуда: scope.$apply Входит? Это явно для запуска цикла дайджеста, когда Angular не знает, что ему нужно. (И если вы используете его, когда Angular знает, что ему нужен цикл дайджеста, вы получите вложенный цикл дайджеста и ошибку «inprog», которую вы заметили.) Here's the doc link, из которого я цитирую: «$ apply() используется для выполнения выражения в угловом из-за угла углового каркаса ». Вы должны использовать его, например, при ответе на обработчик событий, настроенный с помощью неагломеративных методов - прямые привязки событий DOM, jQuery, socket.io и т. Д. Если вы используете эти механизмы в приложении Angular, это часто лучше всего обернуть их в директиву или службу, которая обрабатывает интерфейс с угловым и неглазым, поэтому остальной части вашего приложения не придется беспокоиться об этом.

(scope.$apply фактически обертка scope.$digest, который также управляет обработкой исключений. Это не очень ясно из документации. Я считаю, это легче понять название/поведение $digest, а затем рассмотреть $apply быть «дружелюбнее версия $digest, которую я фактически должен использовать ».)

Последнее примечание к $apply; он принимает аргумент обратного вызова функции, и вы должны выполнять работу внутри этого обратного вызова. Если вы выполните некоторую работу, а затем позвоните по номеру $apply без каких-либо аргументов, она будет работать, но в этот момент это то же самое, что и $digest. Так что если вы сделал нужно использовать $apply здесь, он должен выглядеть как:

scope.buttonClick = function() { scope.$apply(function() { scope.value = newValue; }); });

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