AngularJS指令不会更新范围variables更改

我试着写一个小指令,用另一个模板文件来包装它的内容。

此代码:

<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 = /^([\s\S]*?){{content}}([\s\S]*)$/g; var result = regexp.exec(layout); var templateWithLayout = result[1] + element.html() + result[2]; element.html($compile(templateWithLayout)(scope)); }); } } 

});

我的问题:

当我在模板中使用范围variables(在布局模板或布局标签内),例如。 {{whatever}}它刚开始工作。 如果我更新whatevervariables,该指令不再更新。 整个链接function只会触发一次。

我认为,AngularJS不知道,这个指令使用范围variables,因此它不会被更新。 但我不知道如何解决这个问题。

你应该创build一个绑定的范围variables,并观察其变化:

 return { restrict: 'E', scope: { name: '=' }, link: function($scope) { $scope.$watch('name', function() { // all the code here... }); } }; 

我也需要这个问题的解决scheme,我用这个线程的答案来提出以下几点:

 .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> 

该指令用于基于从服务器检索的数据集dynamic加载报告模板。

它在scope.data属性上设置一个监视,并且每当这个被更新时(当用户从​​服务器请求一个新的数据集时),它加载相应的指令来显示数据。

你需要告诉Angular你的指令使用一个范围variables:

您需要将范围的某些属性绑定到您的指令:

 return { restrict: 'E', scope: { whatever: '=' }, ... } 

然后$watch它:

  $scope.$watch('whatever', function(value) { // do something with the new value }); 

有关更多信息,请参阅有关指令的Angular文档 。

我发现了一个更好的解决scheme:

 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) 

同样,你可以在你的指令模型,所以如果模型自动更新您的观察方法将更新您的指令。

我知道这是一个古老的主题,但如果有任何发现像我自己:

当我需要我的指令更新“父范围”更新时,我使用了下面的代码。 如果我做错了,请一定纠正我,因为我仍然在学习angular度,但这是做我所需要的;

指示:

 directive('dateRangePrint', function(){ return { restrict: 'E', scope:{ //still using the single dir binding From: '@rangeFrom', To: '@rangeTo', format: '@format' }, controller: function($scope, $element){ $scope.viewFrom = function(){ return formatDate($scope.From, $scope.format); } $scope.viewTo = function(){ return formatDate($scope.To, $scope.format); } function formatDate(date, format){ format = format || 'DD-MM-YYYY'; //do stuff to date... return date.format(format); } }, replace: true, // note the parenthesis after scope var template: '<span>{{ viewFrom() }} - {{ viewTo() }}</span>' } }) 

我不知道为什么没有人build议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>' }; } angular .module('app') .directive('fooDirective', fooDirective) .controller('FooDirCtrl', FooDirCtrl); 

小提琴玩耍,这里我们改变controller的范围值,并自动directive updates on scope changedirective updates on scope changehttp://jsfiddle.net/spechackers/1ywL3fnq/