指令未加载范围变量
Directive isn't loading scope variable
所以我有一个非常简单的指令,它应该执行一个 jquery 插件函数:
angular.module('myproject.directives').directive('starRating', function () {
return {
restrict: 'A',
scope: {
rating: '='
},
link: function (scope, elem, attr) {
console.log('rating', scope.rating);
elem.barrating({
theme: 'css-stars',
readonly: true
});
elem.barrating('set', scope.rating);
}
};
});
这里是 HTML:
<select class="service-rating"
ng-show="!!currentJob.Review.ServiceRating"
star-rating rating="currentJob.Review.ServiceRating">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
'currentJob' 变量仅在 $http 调用后设置,但是 div 仅设置为在填充后显示。日志为 scope.rating 返回 'null',但是如果我自己记录 'scope',它会清楚地显示按预期填充的 'rating' 属性。
此外,如果我只是为 'rating' 属性输入一个硬编码数字,指令将按预期工作。
我不太确定哪里出错了?有什么想法吗?
本质上问题是,当您使用 ng-show
时,您的指令在从 Ajax
检索到 star
值之前加载到 DOM 树中,它已处理并且 barrating
附加到 DOM 并具有 star
值 0
。基本上 ng-show
所做的是,它只是在 html 上隐藏或显示 DOM,只需在 [=42= 上切换 display
css 属性 ].
所以你可以有两个选项来让你的星形组件工作。
- 使用
ng-if
代替ng-show
在组件内部使用 $watch
来更新 star
评级(这将是一个很好的解决方案)。
link: function (scope, elem, attr) {
console.log('rating', scope.rating);
elem.barrating({
theme: 'css-stars',
readonly: true
});
scope.$watch('star', function(newValue){
elem.barrating('set', newValue);
});
}
- 您可以将两者结合起来。仅当您使用
ng-if
进行评分时才显示评分,然后 $watch
会注意评分的任何变化以在 barrating
元素上更新。
更改指令以响应评级的变化:
app.directive('starRating', function () {
return {
restrict: 'A',
scope: false,
link: function (scope, elem, attr) {
elem.barrating({
theme: 'css-stars',
readonly: true
});
scope.$watch(attr.rating, function (newValue) {
elem.barrating('set', newValue);
console.log('rating', newValue);
});
}
};
});
以这种方式编码,在每个摘要周期中,观察者检查 rating
属性定义的 Angular 表达式的更改,并适当更新 barrating
插件。
更新
I did think of using a watch but I was curious as to why my original setup didn't work.
原始设置不起作用,因为它仅在指令初始化时设置一次星级。由于指令初始化后数据从服务器到达,插件看不到新数据。通过使用手表,每次控制器更改变量时设置都会更新,包括值从服务器到达的时间。
另请注意,其他答案将手表硬连接到特定范围变量(不明智)。更明智的做法是使用属性来声明特定范围的变量。它使指令更加通用。
当指令缺少使用 AngularJS 绑定的模板时,避免隔离作用域 更为明智。如本例所示,将监视直接放在属性上。
所以我有一个非常简单的指令,它应该执行一个 jquery 插件函数:
angular.module('myproject.directives').directive('starRating', function () {
return {
restrict: 'A',
scope: {
rating: '='
},
link: function (scope, elem, attr) {
console.log('rating', scope.rating);
elem.barrating({
theme: 'css-stars',
readonly: true
});
elem.barrating('set', scope.rating);
}
};
});
这里是 HTML:
<select class="service-rating"
ng-show="!!currentJob.Review.ServiceRating"
star-rating rating="currentJob.Review.ServiceRating">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
'currentJob' 变量仅在 $http 调用后设置,但是 div 仅设置为在填充后显示。日志为 scope.rating 返回 'null',但是如果我自己记录 'scope',它会清楚地显示按预期填充的 'rating' 属性。
此外,如果我只是为 'rating' 属性输入一个硬编码数字,指令将按预期工作。
我不太确定哪里出错了?有什么想法吗?
本质上问题是,当您使用 ng-show
时,您的指令在从 Ajax
检索到 star
值之前加载到 DOM 树中,它已处理并且 barrating
附加到 DOM 并具有 star
值 0
。基本上 ng-show
所做的是,它只是在 html 上隐藏或显示 DOM,只需在 [=42= 上切换 display
css 属性 ].
所以你可以有两个选项来让你的星形组件工作。
- 使用
ng-if
代替ng-show
在组件内部使用
$watch
来更新star
评级(这将是一个很好的解决方案)。link: function (scope, elem, attr) { console.log('rating', scope.rating); elem.barrating({ theme: 'css-stars', readonly: true }); scope.$watch('star', function(newValue){ elem.barrating('set', newValue); }); }
- 您可以将两者结合起来。仅当您使用
ng-if
进行评分时才显示评分,然后$watch
会注意评分的任何变化以在barrating
元素上更新。
更改指令以响应评级的变化:
app.directive('starRating', function () {
return {
restrict: 'A',
scope: false,
link: function (scope, elem, attr) {
elem.barrating({
theme: 'css-stars',
readonly: true
});
scope.$watch(attr.rating, function (newValue) {
elem.barrating('set', newValue);
console.log('rating', newValue);
});
}
};
});
以这种方式编码,在每个摘要周期中,观察者检查 rating
属性定义的 Angular 表达式的更改,并适当更新 barrating
插件。
更新
I did think of using a watch but I was curious as to why my original setup didn't work.
原始设置不起作用,因为它仅在指令初始化时设置一次星级。由于指令初始化后数据从服务器到达,插件看不到新数据。通过使用手表,每次控制器更改变量时设置都会更新,包括值从服务器到达的时间。
另请注意,其他答案将手表硬连接到特定范围变量(不明智)。更明智的做法是使用属性来声明特定范围的变量。它使指令更加通用。
当指令缺少使用 AngularJS 绑定的模板时,避免隔离作用域 更为明智。如本例所示,将监视直接放在属性上。