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

时间:2022-03-14 12:13:30

EDIT: Forked @EliteOctagon's plunker and oddly it's working! Can't understand why the code below isn't. http://plnkr.co/edit/y8uvulA9RHQ1Y9mwzin1

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

EDIT2: Forked the previous plunker and added a $timeout to controller's logic and it stopped working! Guess it's really loading order. Check it out: http://plnkr.co/edit/ivmGQmEHTatNzBWhppyf

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

I'm new to angular and can't get my head wrapped around directive isolate scopes.

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

I need to create a directive to print out a <span/> in my page with info regarding and object in the view controller.

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

What I was trying to do is isolate the directive scope and pass the object through an attribute with two-way binding (see code below). However, when trying to access the object in the link function of the directive it always comes out as undefined.

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

What am I missing here?

我在这里想念的是什么?

Thank you in advance guys.

提前谢谢你们。

Directive use in html view template:

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

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

Directive JS code

指令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 个解决方案

#1


8  

Wrap the directive's party scope variable in a watcher and wait for it to be initialized. In your case you don't do this and so all your logic is being run before scope.party is assigned.

将指令的派对范围变量包装在观察程序中并等待它被初始化。在你的情况下,你不这样做,所以你的所有逻辑都在分配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


9  

I don't think this is an issue with load order. From what I can tell the code you provided should function. Here is a plunker with a working example: http://plnkr.co/edit/Bsn3Vyjrmb311b8ykzU1 There is also logging to the console, which verifies that scope.party is initialized with the correct value on load.

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

Click on the live preview (the Eye Icon on the right sidebar) to view the example.

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

Also, here is a diagram that showed up in my twitter feed the other day that I found very useful for explaining isolate scope in an understandable way. Hope this helps :-)

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

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

#3


0  

In my case, the reason why it was undefined was because the timing was incorrect. Say you have a directive that shows a list of products:

在我的情况下,它未定义的原因是因为时机不正确。假设您有一个显示产品列表的指令:

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

And you define it like so:

你定义它是这样的:

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

If the list of products comes from an HTTP request, it is very likely that the directive will be instantatied before the products are loaded, therefore the console.log prints undefined.

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

One solution is to instantiate the directive after the items are loaded. This will ensure that the link function runs after the items are loaded.

一种解决方案是在加载项目后实例化指令。这将确保链接功能在加载项目后运行。

So, either wrap the directive with an ng-if, like this:

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

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

Or use wbeange's answer to watch the model for changes.

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

#1


8  

Wrap the directive's party scope variable in a watcher and wait for it to be initialized. In your case you don't do this and so all your logic is being run before scope.party is assigned.

将指令的派对范围变量包装在观察程序中并等待它被初始化。在你的情况下,你不这样做,所以你的所有逻辑都在分配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


9  

I don't think this is an issue with load order. From what I can tell the code you provided should function. Here is a plunker with a working example: http://plnkr.co/edit/Bsn3Vyjrmb311b8ykzU1 There is also logging to the console, which verifies that scope.party is initialized with the correct value on load.

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

Click on the live preview (the Eye Icon on the right sidebar) to view the example.

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

Also, here is a diagram that showed up in my twitter feed the other day that I found very useful for explaining isolate scope in an understandable way. Hope this helps :-)

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

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

#3


0  

In my case, the reason why it was undefined was because the timing was incorrect. Say you have a directive that shows a list of products:

在我的情况下,它未定义的原因是因为时机不正确。假设您有一个显示产品列表的指令:

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

And you define it like so:

你定义它是这样的:

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

If the list of products comes from an HTTP request, it is very likely that the directive will be instantatied before the products are loaded, therefore the console.log prints undefined.

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

One solution is to instantiate the directive after the items are loaded. This will ensure that the link function runs after the items are loaded.

一种解决方案是在加载项目后实例化指令。这将确保链接功能在加载项目后运行。

So, either wrap the directive with an ng-if, like this:

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

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

Or use wbeange's answer to watch the model for changes.

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