我尝试编写一个小指令,用其他模板文件包装其内容。
此代码:
<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));
});
}
}
});
我的问题:
当我在模板中使用范围变量时(在布局模板中或布局标签内),例如。 {{whatever}}
它最初起作用。如果我更新whatever
变量,则指令不再更新。整个链接功能只会触发一次。
我认为,AngularJS不知道该指令使用范围变量,因此不会更新。但我不知道如何解决这个问题。
答案 0 :(得分:81)
您应该创建一个绑定范围变量并观察其更改:
return {
restrict: 'E',
scope: {
name: '='
},
link: function(scope) {
scope.$watch('name', function() {
// all the code here...
});
}
};
答案 1 :(得分:41)
我也需要这个问题的解决方案,我使用这个帖子中的答案来提出以下内容:
.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>
此指令用于根据从服务器检索的数据集动态加载报告模板。
它在scope.data属性上设置监视,并且每当更新时(当用户从服务器请求新数据集时),它会加载相应的指令以显示数据。
答案 2 :(得分:16)
您需要告诉Angular您的指令使用范围变量:
您需要将范围的某些属性绑定到您的指令:
return {
restrict: 'E',
scope: {
whatever: '='
},
...
}
然后$watch
:
$scope.$watch('whatever', function(value) {
// do something with the new value
});
有关详细信息,请参阅Angular documentation on directives。
答案 3 :(得分:8)
我找到了一个更好的解决方案:
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>
答案 4 :(得分:2)
你应该密切关注你的范围。
以下是如何做到这一点:
<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)
同样,您可以在指令中建模,因此如果模型自动更新,您的监视方法将更新您的指令。
答案 5 :(得分:2)
我知道这是一个古老的主题,但万一发现这个像我一样:
当我需要我的指令在&#34;父范围&#34;时更新值时,我使用了以下代码。更新。如果我做错了,请务必纠正我,因为我仍在学习角度,但这样做了我所需要的;
指令:
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>'
}
})
答案 6 :(得分:0)
我们可以试试这个
$scope.$apply(function() {
$scope.step1 = true;
//scope.list2.length = 0;
});
答案 7 :(得分:0)
一个简单的解决方案是使范围变量成为 object 。然后使用{{ whatever-object.whatever-property }}
访问内容。该变量未更新,因为JavaScript通过 value 传递了 Primitive 类型。而对象是通过引用传递的,它可以解决问题。
答案 8 :(得分:-1)
我不确定为什么还没有人建议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/