带有ng-repeat的AngularJS指令未渲染。

7
问题在于我需要管理从服务中检索的糖果列表。我创建的指令在HTML中硬编码元素时似乎可以工作,但是当我尝试使用ng-repeat动态分配糖果时出现了问题。
HTML
<div ng-controller="GumballsCtrl">

<h1>Working</h1> 
    <ul>
        <li ng-repeat="gumball in Gumballs">
            <div class="gumballColor{{gumball.color}}">{{gumball.color}}</div>
        </li>
    </ul>

<h1>Problem - Expecting the same result at the work version</h1>

    <ul>
        <li ng-repeat="gumball in Gumballs">
            <mygumball id={{gumball.id}} color="{{gumball.color}}">{{gumball.color}}</mygumball>
        </li>
    </ul>
</div>

JavaScript

var myApp = angular.module('myApp', []);

function GumballsCtrl($scope, Gumballs) {
    $scope.Gumballs = Gumballs;
}

myApp.factory('Gumballs', function () {
    return [{
        id: '1',
        color: 'R'
    }, {
        id: '2',
        color: 'G'
    }, {
        id: '3',
        color: 'B'
    }, {
        id: '4',
        color: 'Y'
    }, {
        id: '5',
        color: 'G'
    }];
});

myApp.directive('mygumball', function ($scope) {
    return {
        restrict: 'E',

        scope: {},

        link: function (scope, element, attrs) {
            if (attrs.color !== '' && attrs.color !== undefined) {
                scope.color = attrs.color;
            } else {
                scope.color = 'U';
            }
        },

        replace: true,

        template: "<div class='gumballColor{{color}}'>{{color}}</div>"
    };
});

CSS

.gumballColorR {
    font-size: 12px;
    text-align: center;
    padding: 2px;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    border: solid 1px #CC0000;
    background-color: #FF0000;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    margin-top: 5px;
}
.gumballColorG {
    font-size: 12px;
    text-align: center;
    padding: 2px;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    border: solid 1px #00CC00;
    background-color: #00FF00;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    margin-top: 5px;
}
.gumballColorB {
    font-size: 12px;
    text-align: center;
    padding: 2px;
    color: #FFFFFF;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    border: solid 1px #0000CC;
    background-color: #0000FF;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    margin-top: 5px;
}
.gumballColorY {
    font-size: 12px;
    text-align: center;
    padding: 2px;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    border: solid 1px #CCCC00;
    background-color: #FFFF00;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    margin-top: 5px;
}
.gumballColorU {
    font-size: 12px;
    text-align: center;
    padding: 2px;
    -moz-border-radius: 10px;
    -webkit-border-radius: 10px;
    border-radius: 10px;
    border: solid 1px #CCCCCC;
    background-color: #DDDDDD;
    width: 15px;
    height: 15px;
    margin-left: 5px;
    margin-top: 5px;
}

当使用ng-repeat传递指令时,id和color属性最终变为未定义,但在HTML中硬编码时有效。

http://jsfiddle.net/i3sik/NGB9v/22/

1个回答

10

问题出在你的隔离作用域上。通过使用 scope: {},你创建了一个新的、隔离的作用域来处理该元素。隔离作用域不会继承父级作用域。所有具有隔离作用域的指令上的属性和内容都在隔离作用域的上下文中进行评估。在隔离作用域中不存在gumball,因此一切都变成了未定义。

要解决这个问题,你有两个选择:(1)移除隔离作用域(例如,使用scope: true来创建子作用域);或者(2)将值绑定到你的隔离作用域中。

为了将你的属性绑定到作用域变量上,你只需要指定作用域和你想要的绑定类型即可:

scope: {
  id: '@',
  color: '@'
},

这段话表示要在父级作用域的上下文中插值属性idcolor,然后将其添加到作用域中。您可以删除link函数内的所有逻辑 - 这将为您完成。

但是这仍然留下了指令内部内容的问题。要在父级作用域的上下文中插值它们,您需要进行传输:

transclude: true,
template: "<div class='gumballColor{{color}}' ng-transclude></div>"

转置将元素的内容插值到父级作用域的新子级,例如,gumball仍然是已定义的。

通过这两个更改,您的指令将按预期工作。

如果您对要使用哪个作用域感到困惑,这里还有一个可能有所帮助的SO问题:编写指令时,如何确定需要没有新作用域、新子作用域或新隔离作用域?


附注:即使没有隔离作用域,在您的link函数中确定属性值的逻辑也不会起作用。执行顺序是重要部分,大致为:编译器->控制器->链接->插值。在插值完成之前,您的属性没有值。因此,您的检查将无法正常工作。

话虽如此,您可以在插值后的属性上设置一个$observe;即使没有传递任何值,$observe也将始终首次触发。您可以使用此来设置默认值。$observe也非常高效。

attrs.$observe( 'attr1', function(val) {
  if ( !angular.isDefined( val ) ) {
    scope.attr1 = 'defaultValue';
  }
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接