0

我在理解指令属性 vs 范围变量传递给指令时遇到一些困难。
我正在制定一个动态加载正确模板的指令,具体取决于内容类型。 当我使用linker功能,使用范围变量做切换的事情工作良好。动态模板和范围变量

如果我使用:

<mydirective ng-repeat="item in items" content="item" type="item.type"></mydirective> 

我通过包含数据的对象content用于填充模板和该对象内我有一个type属性我使用用于选择的模板。
这是我的指令定义(一些代码省略):

//[...] 
linker = function(scope, element, attrs){ 
    //templates is a service I use to retrieve the templates 
    loaderPromise = templates.getTemplate(scope.content.type) 
    promise = loaderPromise.success(function(html){ 
     element.html(html) 
    }).then(function(response){ 
     element.replaceWith($compile(element.html())(scope)) 
    }) 
} 

return { 
    restrict : "E", 
    replace: true, 
    scope: { 
     'content': "=" 
    }, 
    link : function(scope, element, attributes){ 
     linker(scope, element, attributes) 
    } 
    //[...] 
} 

现在,而不是这个,我想一个函数传递给“templateUrl”,像这样:

return { 
    restrict : "E", 
    replace: true, 
    scope: { 
     'content': "=" 
    }, 
    templateUrl : function(element, attributes) { 
     // I don't access to the scope but only to the attributes 
     attributes.$observe(attributes.content.type, function(value){ 
     if(value) { 
      // templates is a service 
      return templates.getTemplateUrl(value.type) 
     } 
     }) 
    } 
    //[...] 
} 

现在,这将不起作用要么我观察attributes.content.typeattributes.type。这些属性将始终为undefined

我也尝试添加传递给该指令type为范围变量:

scope: { 
     'content': "=" 
     'type': '=' 
     } 

但被继续undefined

所以基本上我真的很困惑的使用attributes VS使用variable scopes

编辑:

我猜它是与NG-重复。如果我把一个断点上线

attributes.$observe(attributes.content.type, function(value){ 

,我检查attributes值我得到

$$element: jQuery.fn.init[1] 
$attr: Object 
content: "item" 
ngRepeat: ""item in items" 

,所以我想content尚未进行评估,这就是为什么attributes.content.typeundefined。想知道为什么..

回答

2

您的templates服务是同步的还是异步的? templateUrl函数必须返回一个表示Url的字符串,并且不会支持返回一个promise(为了确保,我必须在Plunker中测试它)。

如果它同步返回一个字符串,那么我不知道为什么attributes.type === undefined

类似以下工作:

templateUrl : function(element, attributes) { 
    return attributes.type; 
} 

我(稍微修改后的版本),你的代码试了一下,它工作得很好 - 这里的plunker

至于你的问题,使用scope因为当你实现单向(即一个指令反应值的变化)或双向绑定(即一个指令发生反应,并在父范围变更的值)。使用属性作为初始化值。

编辑︰ 我现在更好地理解这个问题。这里有几件事情:应插分配给type属性

的值(即在大括号):

<mydirective ng-repeat="item in items" content="item.content" type="{{item.type}}"></mydirective> 

,因为你需要的插值字符串值,而不是对象(除非在范围定义中将其定义为"=type"),您也不会获得该对象。

不幸的是,您将不幸在templateUrl函数中遇到问题,这与ng-repeat无关。这是因为这些值尚未在templateUrl函数或compile函数中进行插值,所以您将获得“{{item.type}}”作为字符串。这对使用$interpolate服务也没有帮助,因为您还没有合适的范围。为解决这一

一种方式是追加和$compile<div ng-include>在指向您所要求的模板链接功能:

link: function(scope, elem, attr){ 
    var template = attr.type || "template1"; 
    var templateUrl = template + ".html"; 
    elem.append("<div ng-include='\"" + templateUrl + "\"'></ng-include>"); 

    $compile(elem.contents())(scope); 
}, 

下面是完整的plunker

+0

我的'模板'服务是同步的。我已经更新了这个问题,我想这与ng-repeat更相关,但并非100%肯定。 – Leonardo 2014-10-05 14:55:58

+0

@Leonardo,我编辑了答案 – 2014-10-06 15:38:20

+0

所以基本上你的最后一个解决方案看起来与我的第一个解决方案非常相似一个工作),不是吗? – Leonardo 2014-10-22 13:34:14