【问题标题】:AngularJS Scope differences between 1.0.x and 1.2.xAngularJS 1.0.x 和 1.2.x 的作用域差异
【发布时间】:2013-11-25 11:21:16
【问题描述】:

随着下一个稳定的 AngularJS 的发布,我正在将我的应用程序从版本 1.0.8 迁移到 1.2

在 AngularJS 1.0.8 中,可以为 follow 等指令设置隔离范围。然后该指令将使用它自己的test() 函数而不是控制器的test() 函数。

HTML

<my-dialog property="something">
    <button ng-click="test()">Load Test</button>
    Check out the test: "{{ testMessage }}"
</my-dialog>

Javascript

  .controller('Ctrl', function(scope) {
    scope.test = function () {
       scope.testMessage = 'CTRL Test loaded! Whooops.';
    }
  })

  .directive('myDialog', function() {
    return {
      restrict: 'E',
      scope: {
          property: '='
      },
      link: function(scope) {
          scope.test = function () {
            scope.testMessage = 'Isolated Test loaded. Yes!';
          }
      }
    };

在 AngularJS 1.2 中,这种行为不再起作用。点击按钮立即触发控制器的test() 函数。

查看这个 jsFiddle 比较:

究竟发生了什么变化?如何重现旧行为?

注意

我发现我可以将指令模板放在一个额外的 HTML 文件中或将其编译为字符串以使其正常工作 (jsFiddle) 但在我的情况下似乎太多了,因为模板是固定的并且正在拆分多个部分 HTML 文件的 HTML 很麻烦。

编辑

@elclanr's answer 在没有其他要共享的属性时可以正常工作。我更新了the jsFiddle 以传递一些任意属性。我现在应该如何进行?

【问题讨论】:

  • 只是scope: truejsfiddle.net/rug3J/1。我还建议遵循约定并将其命名为 scope 而不是 $scope 当它不是依赖注入时。
  • @elclanrs 哦,谢谢!那很简单。您能否将其发布为答案,我可以将此问题标记为已回答。
  • 有趣-我刚刚检查过,这在 rc3 和现在之间发生了变化。除了将范围设置为 true,您还可以使用:scope: {test: '&amp;'}。我确认它可以按预期工作-将测试通过隔离范围。
  • @KayakDave 感谢您提供的文档,这似乎很有意义。 {test: '&amp;'} 不适合我,因为我不想使用控制器的 test() 函数。
  • 只是为了确保一切都清楚 {test: '&'} 将导致 ng-click="test()" 调用您的指令的 test() 而不是控制器的。与将范围设置为 true 的行为相同 - 除了您将对其他所有内容使用隔离范围。

标签: javascript angularjs angularjs-directive


【解决方案1】:

看起来这是重大更改的预期结果:github.com/angular/angular.js/commit/… 被拉入 1.2.0(在 rc3 之后)(https://github.com/angular/angular.js/blob/master/CHANGELOG.md - 请参阅 1.2.0 的第一个重大更改 - $compile):

修复了隔离范围泄漏到同一元素上的其他指令的问题。

隔离范围现在仅可用于请求它的隔离指令及其模板。

一个非隔离指令不应该在同一个元素上获得一个隔离指令的隔离作用域,而是他们将接收原始作用域(这是新创建的隔离作用域的父作用域)。

还可以查看此讨论:github.com/angular/angular.js/issues/4889

值得注意的是:“隔离范围仅适用于模板,而不适用于不是由指令贡献的标记。在1.2之前,隔离范围有一个导致这种泄漏的错误。隔离的要点范围是它只适用于声明它的指令,而不适用于其他指令或标记。"(来自 tbosch)

1.2.0 之前,同一 DOM 元素上的所有内容都共享相同的范围。 因此 1.2.0 对具有隔离范围的指令的工作方式进行了重大更改。

【讨论】:

  • 嘿,很好的答案,现在的行为是有意义的。
【解决方案2】:

为了将普通标记与指令特定模板和函数结合起来,需要像这样使用 transclude 选项:

请参阅:jsFiddle

HTML

<div ng-app="myApp">
    <div ng-controller="Ctrl">
        <my-directive property="{{ something }}">
            <p>{{ text }}</p>
        </my-directive>
    </div>
</div>

Javascript

.controller('Ctrl', ['$scope', function($scope) {
    $scope.text = 'This is a controllers text.';
    $scope.something = 'This is another controllers text.';
}])
.directive('myDirective', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: '<button ng-click="test()">Fire directives function</button><div ng-transclude></div><p>{{ property }}</p>',
        scope: {
            property: '@'
        },
        link: function(scope) {
            scope.test = function () {
                scope.property = 'Loaded directives text.';
            }
        }
    };
});

这对我来说现在很好,但应该注意的是不能覆盖范围的现有属性。

【讨论】:

    【解决方案3】:

    设置scope: true 应该可以解决问题。 http://jsfiddle.net/rug3J/1。我还建议遵循约定并将其命名为 scope 而不是 $scope 当它不是依赖注入时:

    .directive('myDialog', function() {
      return {
        restrict: 'E',
        scope: true,
        link: function(scope) {
          scope.test = function () {
            scope.testMessage = 'Isolated Test loaded. Yes!';
          }
        }
      };
    

    【讨论】:

    • 你有一个理想的为什么当我传递其他属性时它不起作用?我相应地更新了我的问题和 jsFiddle。
    • 似乎只要设置了隔离范围,控制器的范围就会优先。 TBH 我不确定自 Angular 1.0.8 以来发生了什么改变,打破了以前的行为。
    • 如果您找到解决方案,请回帖,我现在很好奇,在不太好的文档中没有找到任何相关内容...
    • 我可以确认,通过将 scope:true 设置为我们的隔离指令,我们解决了当前 1.2.x 迁移中的问题。
    猜你喜欢
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    • 2017-03-02
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    相关资源
    最近更新 更多