Angular.js:范围中的指令对象始终未定义

时间:2014-11-12 18:29:02

标签: javascript angularjs angularjs-directive angularjs-scope

编辑:分叉@EliteOctagon的plunker奇怪它正在工作!无法理解为什么下面的代码不是。 http://plnkr.co/edit/y8uvulA9RHQ1Y9mwzin1

EDIT2:分叉前一个plunker并为控制器的逻辑添加$ timeout,它停止工作!猜猜它真的是在加载订单。请查看:http://plnkr.co/edit/ivmGQmEHTatNzBWhppyf

我是棱角分明的新手,无法将我的脑袋缠绕在指令隔离范围内。

我需要创建一个指令,在我的页面中打印出<span/>,其中包含视图控制器中的信息和对象。

我试图做的是隔离指令范围并通过具有双向绑定的属性传递对象(请参阅下面的代码)。但是,当尝试访问指令的link函数中的对象时,它总是以未定义的形式出现。

我在这里缺少什么?

先谢谢你们。

在html视图模板中使用指令:

<party-starts party="party"></party-starts>

指令JS代码

.directive('partyStarts', function(){
    return {
        restrict: 'E',
        template: '<div id="partyStart><i class="icon ion-pin"></i> </div>',
        scope: {
            party: '='
        },
        link: function(scope, el) {
            var party = scope.party;
            var icon = el.find('i');
            var statusStr = angular.element('<span/>');
            var final;

            console.log('scope '+scope);

            if(party.Diatodo){
                if(party.datahora.isSame(moment(), 'day') || party.datahora.isSame(moment().add(1, 'd'), 'day')){
                    icon.css({
                        'color': 'green'            
                    });
                    statusStr.text(' É hoje');
                    el.append(statusStr);
                }else{
                    icon.css({
                        'color': '#999'            
                    });
                    statusStr.text(' Começa em '+party.datahora.fromNow());
                    el.append(statusStr);
                }
                return;
            }

            if(party.datahora.unix() == party.datahoraf.unix()){
                final = party.datahora.clone().add(1, 'd').hour(6);
            }else{
                final = party.datahoraf;
            }

            if(party.datahora.twix(final).isCurrent()){
                icon.css({
                    'color': 'green'            
                });
                statusStr.text(' Começou há '+party.datahora.fromNow());
                el.append(statusStr);
            }else if(party.datahora.twix(final).isFuture()){
                icon.css({
                    'color': '#999'            
                });
                statusStr.text(' Começa em '+party.datahora.fromNow());
                el.append(statusStr);
            }else{
                icon.css({
                    'color': 'red'            
                });
                statusStr.text(' Já terminou');
                el.append(statusStr);
            }
        }
    };
})

3 个答案:

答案 0 :(得分:9)

我不认为这是加载顺序的问题。据我所知,您提供的代码应该起作用。这是一个带有工作示例的plunker: http://plnkr.co/edit/Bsn3Vyjrmb311b8ykzU1还有一个登录控制台,它会验证scope.party是否在加载时使用正确的值进行初始化。

点击实时预览(右侧边栏上的眼睛图标)查看示例。

此外,这是一个图表,在我的推文提要中显示,我发现这对于以可理解的方式解释隔离范围非常有用。希望这会有所帮助: - )

enter image description here

答案 1 :(得分:8)

将指令的派对范围变量包装在观察程序中并等待它被初始化。在你的情况下,你没有这样做,所以你的所有逻辑都在分配scope.party之前运行。

link: function(scope, el) {

  var watcher = scope.$watch('party', function() {
    if(scope.party === undefined) return;

    // at this point it is defined, do work

    // delete watcher if appropriate
    watcher();
  })
}

答案 2 :(得分:0)

就我而言,之所以未定义是因为时机不正确。假设您有一个显示产品列表的指令:

<my-products products='httpLoadedProducts'>/<my-products>

你定义它是这样的:

.directive('myProducts', function () {
  return {
    restrict: 'E',
    scope: {
      products: '=',
    },
    templateUrl: 'directives/products-template.html',
    link: function (scope, element, attrs) {
       console.log(scope.products);
    }
  }
})

如果产品列表来自HTTP请求,则很可能在产品加载之前指令,因此console.log打印undefined

一种解决方案是在项加载后实例化指令。这将确保在加载项目后运行link函数。

所以,用ng-if包装指令,如下所示:

<div ng-if='httpLoadedProducts'>
   <my-products products='httpLoadedProducts'>/<my-products>
</div>

或者使用wbeange的答案来观察模型的变化。