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}}
它刚开始工作。 如果我更新whatever
variables,该指令不再更新。 整个链接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 change
的directive updates on scope change
。 http://jsfiddle.net/spechackers/1ywL3fnq/