Директивы в AngularJS не обновляет на область изменения переменных
Я попытался написать небольшую директиву, чтобы обернуть ее содержимое с другим файлом шаблона.
этот код:
<layout name="Default">My cool content</layout>
должен иметь этот вывод:
<div class="layoutDefault">My cool content</div>
потому, что макет "по умолчанию" этот код:
<div class="layoutDefault">{{content}}</div>
вот код директивы:
app.directive('layout', function($http, $compile){
return {
restrict: 'E',
link: function(scope, element, attributes) {
var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default';
$http.get(scope.constants.pathLayouts + layoutName + '.html')
.success(function(layout){
var regexp = /^([sS]*?){{content}}([sS]*)$/g;
var result = regexp.exec(layout);
var templateWithLayout = result[1] + element.html() + result[2];
element.html($compile(templateWithLayout)(scope));
});
}
}
});
моя проблема:
когда я использую переменные в шаблон (в шаблоне макета или внутри тега макета), например. {{whatever}} Он просто работает изначально. Если я обновлю whatever переменная, директива больше не обновляется. Все функции связи будет только один раз срабатывает.
Я думаю, что AngularJS не знает, что эта директива использует переменные области видимости и поэтому она не будет обновляться. Но я понятия не имею, как исправить это поведение.
9 ответов:
вы должны создать связанную переменную области и наблюдать за ее изменениями:
return { restrict: 'E', scope: { name: '=' }, link: function(scope) { scope.$watch('name', function() { // all the code here... }); } };
мне также нужно было решение этой проблемы, и я использовал ответы в этой теме, чтобы придумать следующее:
.directive('tpReport', ['$parse', '$http', '$compile', '$templateCache', function($parse, $http, $compile, $templateCache) { var getTemplateUrl = function(type) { var templateUrl = ''; switch (type) { case 1: // Table templateUrl = 'modules/tpReport/directives/table-report.tpl.html'; break; case 0: templateUrl = 'modules/tpReport/directives/default.tpl.html'; break; default: templateUrl = ''; console.log("Type not defined for tpReport"); break; } return templateUrl; }; var linker = function (scope, element, attrs) { scope.$watch('data', function(){ var templateUrl = getTemplateUrl(scope.data[0].typeID); var data = $templateCache.get(templateUrl); element.html(data); $compile(element.contents())(scope); }); }; return { controller: 'tpReportCtrl', template: '<div>{{data}}</div>', // Remove all existing content of the directive. transclude: true, restrict: "E", scope: { data: '=' }, link: linker }; }]) ;включить в свой html:
<tp-report data='data'></tp-report>эта директива используется для динамической загрузки шаблонов отчетов на основе данных, полученных от сервера.
Он устанавливает часы на сферу.свойство data и всякий раз, когда оно обновляется (когда пользователи запрашивают новый набор данных с сервера), он загружает соответствующую директиву покажите данные.
вы должны сказать Angular, что ваша директива использует переменную scope:
вам нужно привязать некоторое свойство области к вашей директиве:
return { restrict: 'E', scope: { whatever: '=' }, ... }а то
$watchэто:$scope.$watch('whatever', function(value) { // do something with the new value });относятся к угловая документация по директивам для получения дополнительной информации.
Я нашел гораздо лучшее решение:
app.directive('layout', function(){ var settings = { restrict: 'E', transclude: true, templateUrl: function(element, attributes){ var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default'; return constants.pathLayouts + layoutName + '.html'; } } return settings; });единственный недостаток я вижу в настоящее время является тот факт, что раскрываемый шаблоны получили в свои собственные рамки. Они получают значения от своих родителей, но вместо того, чтобы изменить значение в родителе, значение сохраняется в собственной, новой дочерней области. Чтобы избежать этого, я использую
$parent.whateverвместоwhatever.пример:
<layout name="Default"> <layout name="AnotherNestedLayout"> <label>Whatever:</label> <input type="text" ng-model="$parent.whatever"> </layout> </layout>
вы должны следить за своим прицелом.
вот как вы можете сделать это:
<layout layoutId="myScope"></layout>ваша директива должна выглядеть как
app.directive('layout', function($http, $compile){ return { restrict: 'E', scope: { layoutId: "=layoutId" }, link: function(scope, element, attributes) { var layoutName = (angular.isDefined(attributes.name)) ? attributes.name : 'Default'; $http.get(scope.constants.pathLayouts + layoutName + '.html') .success(function(layout){ var regexp = /^([\s\S]*?){{content}}([\s\S]*)$/g; var result = regexp.exec(layout); var templateWithLayout = result[1] + element.html() + result[2]; element.html($compile(templateWithLayout)(scope)); }); } } $scope.$watch('myScope',function(){ //Do Whatever you want },true)аналогично вы можете моделировать в своей директиве, поэтому, если модель обновляется автоматически, ваш метод часов обновит вашу директиву.
Я знаю эту старую тему, но в случае, если кто-нибудь найдет это, как я:
я использовал следующий код, когда мне нужна была моя директива для обновления значений при обновлении "родительской области". Пожалуйста, во что бы то ни стало поправьте меня, если я делаю что-то не так, как я все еще учусь угловой, но это сделало то, что мне нужно;
мы можем попробовать этот
$scope.$apply(function() { $scope.step1 = true; //scope.list2.length = 0; });
простое решение состоит в том, чтобы сделать переменную scope объект. Затем получите доступ к содержимому с помощью
{{ whatever-object.whatever-property }}. Переменная не обновляется, потому что JavaScript pass первобытное типа стоимостью. Тогда как объект передает ссылка что решает проблему.
Я не знаю, почему никто еще не предложил
bindToController, который удаляет все эти уродливыеscopes and $watches.Если вы используетеAngular 1.4ниже приведен пример DOM:
<div ng-app="app"> <div ng-controller="MainCtrl as vm"> {{ vm.name }} <foo-directive name="vm.name"></foo-directive> <button ng-click="vm.changeScopeValue()"> changeScopeValue </button> </div> </div>следует
controllerкод:angular.module('app', []); // main.js function MainCtrl() { this.name = 'Vinoth Initial'; this.changeScopeValue = function(){ this.name = "Vinoth has Changed" } } angular .module('app') .controller('MainCtrl', MainCtrl); // foo.js function FooDirCtrl() { } function fooDirective() { return { restrict: 'E', scope: { name: '=' }, controller: 'FooDirCtrl', controllerAs: 'vm', template:'<div><input ng-model="name"></div>', bindToController: true }; } angular .module('app') .directive('fooDirective', fooDirective) .controller('FooDirCtrl', FooDirCtrl);Скрипка, чтобы играть вокруг, здесь мы меняем значение области в
controllerи автоматическиdirective updates on scope change. http://jsfiddle.net/spechackers/1ywL3fnq/
Comments