【问题标题】:Angular - scope variable update in controller function call doesn't get reflected in directive htmlAngular - 控制器函数调用中的范围变量更新不会反映在指令 html 中
【发布时间】:2015-08-23 20:39:47
【问题描述】:

我一直在玩 angular 试图了解它如何管理范围,然后我发现我无法使用函数调用更新指令中的变量。

为了说明这个问题,这是我的简单应用程序: 这个想法是,当您单击切换链接时,菜单应该会显示出来,而当您再次单击它或其他地方时,菜单应该会消失。

angular.module('app', [])
  .controller('DemoController', ['$scope', function($scope) {

  }])
  .directive('dropdown', function() {
    return {
      restrict: 'E',
      transclude: true,
      controller: function($scope) {
        $scope.onBlur = function () {
          // this doesn't actually work
          $scope.showMenu = false;
        };
      },
    };
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body id="body" ng-app="app" ng-controller="DemoController">
  <dropdown ng-transclude>
    <a href="#" ng-click="showMenu = !showMenu" ng-blur="onBlur()">Toggle</a>
    <menu ng-show="showMenu">
      <div>I'm</div>
      <div>the drop-down</div>
      <div>menu</div>
    </menu>
  </dropdown>
</body>

这是我的 plunker 链接:

非工作版本: http://plnkr.co/edit/rfdt5FEoGAOX15RZUsKA?p=preview

工作版本: http://plnkr.co/edit/xMANGDVa8n64OKK3gOgg?p=preview

工作版本和另一个的区别在于工作版本只是使用ng-blur="showMenu = false"而不是调用函数。如果我在控制器函数中调用$scope.$apply(),那么我会得到“$apply already in progress”异常。

我想我一定在这里遗漏了一些东西,但我现在不知道为什么。提前致谢。

【问题讨论】:

  • 不要使用$scope.$apply()。使用$timeout( function(){ .... })。它将避免“已经在进行中”错误。
  • @JeremyThille 这里都不需要。
  • 不过,诀窍仍然存在 =)
  • 真的!值得注意,但也值得注意的是,如果可能的话,两者都不应该使用。 @NSF 您对 $scope.showMenu = false 的使用很好,您在控制器中所做的事情是正确的 - 但是我不禁认为这是由于 Angular 处理焦点/模糊事件的方式

标签: javascript angularjs


【解决方案1】:

关于 $scope.$apply() 函数的第一件事是只有在 $scope.$$phase 为空时才可以调用它(确保它不在 $digest 或 $apply 阶段)

if (!$scope.$$phase) {
   $scope.$apply()
}

在您的第一个 plunker 中仅更改以下内容:

$scope.showMenu = false;
to 
this.showMenu = false;

它的in function和function已经是$scope bind了。

【讨论】:

  • 哇,这完全有效!通过使用console.log,似乎在函数调用内部,“this”指的是原始作用域,而$scope 是一个新作用域。我想知道是否有文档提到为什么会这样。
  • 这是javascript的问题,实际上不是angularjs。你已经在 $scope 下定义了函数,并且这个函数内部的“this”和原来的 $scope 是一样的,但是如果你在函数中使用 $scope,javascript 会将这个变量绑定到完全不同的 $scope。
  • 这就是我得到的 - console.log(this): ChildScope {$$childTail: null, $$childHead: null, $$nextSibling: null, $$watchers: Array[1], $$listeners: Object…}, console.log($scope): Object {$$childTail: ChildScope, $$childHead: ChildScope, $$nextSibling: null, $$watchers: null, $$listeners: Object…} 可能请问第二个作用域是从哪里来的?
  • @NSF 第二个作用域是在您使用ng-transclude 时创建的。我知道这很啰嗦,但这个答案很棒:stackoverflow.com/questions/16653004/…
  • @AlexG 实际上我后来发现这不是 javascript 的问题,但仍然有角度。当使用 transclude 时,angular 创建一个兄弟作用域,它不在指令作用域之下,而是在指令作用域旁边。当函数被调用时,angular 将转入模板中的范围绑定到该函数中的“this”引用。 $scope 变量仍然是完整的指令范围,并且因为它是同级范围,所以更改不会原型继承到另一个范围。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多