【问题标题】:Angular.js: directive object in scope is always undefinedAngular.js:范围内的指令对象始终未定义
【发布时间】:2014-11-12 18:29:02
【问题描述】:

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

EDIT2: 分叉了之前的 plunker,并在控制器的逻辑中添加了 $timeout,但它停止了工作!猜猜它真的是加载顺序。看看吧:http://plnkr.co/edit/ivmGQmEHTatNzBWhppyf

我是 Angular 新手,无法理解指令隔离范围。

我需要创建一个指令以在我的页面中打印出<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);
            }
        }
    };
})

【问题讨论】:

  • 你能用一些代码做一个笨拙的人吗?这是一个空白模板plnkr.co/edit/TkONdJqtD6nSg6s0Da59
  • 只要在父控制器内部定义了$scope.parent,应该没有问题。您是否可能在 ng-if 或 ng-repeat 中使用派对开始,因此无意中创建了新的子范围?
  • 这里没有 ng-repeat 循环,只是传递了控制器范围内的常规对象
  • 使用 $scope.party 的父控制器是什么样的?
  • @EliteOctagon 刚刚用等效代码分叉了你的 plunker,它就可以正常工作......根本无法理解 :( plnkr.co/edit/y8uvulA9RHQ1Y9mwzin1

标签: javascript angularjs angularjs-directive angularjs-scope


【解决方案1】:

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

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

另外,这是前几天在我的 twitter 提要中显示的图表,我发现它对于以易于理解的方式解释隔离范围非常有用。希望这会有所帮助:-)

【讨论】:

  • 很棒的信息图,真的很有用!谢谢! :D 不能投票(没有足够的代表)但我会把它留在这里+1 :)
【解决方案2】:

将指令的方作用域变量包装在观察器中并等待它被初始化。在您的情况下,您不这样做,因此您的所有逻辑都在分配 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();
  })
}

【讨论】:

  • 谢谢!我想你是对的。因为我已经将另一个 plunker 包裹在超时中并且它停止工作。 plnkr.co/edit/ivmGQmEHTatNzBWhppyf
  • 如果超时时间足够长,$timeout 可以使其工作,但使用 $watch 而不是 $timeout,因为您无法定义时间。
  • 是的,就是这样!非常感谢您在 EDIT2 中看到更新的 plunker
  • 我只是将控制器逻辑包装在 $timeout 中以测试您的假设,而不是解决问题,因为我按照您的建议使用了 $watch ! :)
  • @wbeange 为什么要用自定义函数包装 $watch 并反复调用自己? $watch 不是已经在做了吗?
【解决方案3】:

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

<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 的回答来观察模型的变化。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-28
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 2015-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多