具有ng-repeat不渲染的AngularJS指令

use*_*790 7 directive undefined angularjs angularjs-ng-repeat

问题是我必须管理从服务中检索到的胶球列表.当我硬编码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>
Run Code Online (Sandbox Code Playgroud)

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>"
    };
});
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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

传递给指令时的id和color属性在使用ng-repeat传递时最终未定义,但在HTML中进行硬编码时工作.

Jos*_*ler 10

这里的问题是你的隔离范围.通过使用scope: {}您创建了一个新的隔离范围来对该元素进行操作.隔离范围不从父范围继承.具有隔离范围的指令上的所有属性和内容都在隔离范围的上下文中进行评估.gumball隔离范围中不存在,因此所有内容都是未定义的.

您有两种方法可以解决此问题:(1)删除隔离范围(例如scope: true,创建子范围); 或(2)绑定隔离范围中的值.

要将属性绑定到范围变量,只需指定范围和所需的绑定类型:

scope: {
  id: '@',
  color: '@'
},
Run Code Online (Sandbox Code Playgroud)

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

但是,这仍然留下了内容的问题,里面的指令.要在父作用域的上下文中插入它,您需要进行转换:

transclude: true,
template: "<div class='gumballColor{{color}}' ng-transclude></div>"
Run Code Online (Sandbox Code Playgroud)

Transclusion获取元素的内容并相对于父范围的新子项进行插值,例如gumball仍将定义的位置.

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

如果您对使用哪个范围感到困惑,这里有另一个可能有用的SO问题:在编写指令时,如何确定是否不需要新范围,新子范围或新隔离范围?


旁注:即使没有隔离范围,link函数中用于确定属性值的逻辑也不起作用.执行顺序是这里的重要部分,大致是:编译器 - >控制器 - >链接 - >插值.在插值完成之前,您的属性没有任何值.所以你的检查不起作用.

也就是说,您可以设置$observe插值属性; 该$observe总会触发一次,即使没有传递的值.您可以使用它来设置默认值.$observe也很有效率.

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