指令未加载范围变量

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 并具有 star0。基本上 ng-show 所做的是,它只是在 html 上隐藏或显示 DOM,只需在 [=42= 上切换 display css 属性 ].

所以你可以有两个选项来让你的星形组件工作。

  1. 使用ng-if代替ng-show
  2. 在组件内部使用 $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);
        });
    }
    
  3. 您可以将两者结合起来。仅当您使用 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 绑定的模板时,避免隔离作用域 更为明智。如本例所示,将监视直接放在属性上。