隔离范围视图绑定

Isolated Scope View binding

我使用独立作用域指令已经有一段时间了,观察它的行为时我想到了一个问题:

为什么我不能将我在指令继承范围内定义的变量直接绑定到视图?

让我在这个代码笔上展示一个例子: http://codepen.io/anon/pen/VLKjrv

当我在指令控制器中创建一个新的 $scope 变量并尝试将其绑定到视图时,它不起作用。 另一方面,当我将该变量绑定到来自模板指令属性的 html 上时,它确实有效。

查看代码:

<body ng-app="isolated-test-app">
<section ng-controller="isolatedTestCtrl">
    <article>
      <h1>test1</h1>
        <div isolated-directive binding-from-attr="test">
            <span ng-bind="test"></span>
            <span ng-bind="test2"></span>
        </div>
      <h1>test2</h1>
        <div isolated-directive-number-two binding-from-attr="test">
        </div>

    </article>
</section>

angular.module('isolated-test-app', [])

.controller('isolatedTestCtrl', function isolatedTestCtrl($scope){
    $scope.test = 'Binded from parent controller';
})

.directive('isolatedDirective', function isolatedDirective(){

    var directive = {
        scope: {
          bindingFromAttr: '=',
        },
        controller: function directiveController($scope){
           $scope.test2 = 'Binded from directive controller!';
        },
    };

    return directive;
})

.directive('isolatedDirectiveNumberTwo', function isolatedDirective2(){

    var directive = {
        scope: {
          bindingFromAttr: '=',
        },
        template:'<span ng-bind="bindingFromAttr"></span>\
                  <span ng-bind="test2"></span>',
        controller: function directiveController($scope){
           $scope.test2 = 'Binded from directive controller!';
        },
    };

    return directive;
})

test1

Binded from parent controller

test2

Binded from parent controller

Binded from directive controller!

我期待 test1 上 test2 的结果。

为什么会这样?

这是我根据 http://codepen.io/anon/pen/MwjjBw

中的实验得出的猜测

所以对于测试 1,指令范围没有 test/test2,因为 dom 对象属于控制器。因此,为了更新它,您必须使用

$scope.$parent.test2 = "" ; 

并且对于测试 2,由于模板是作为指令的一部分创建的,因此 dom 对象属于指令并且也可由控制器访问(我猜 $compile 将其添加到控制器 scope/watch ).

您还可以看到 test1 没有任何观察者,因为没有绑定发生。

指令模板指令元素的内容在适用范围方面存在差异。

isolate scope (scope: {}) 指令中,isolate 范围适用于模板,但不适用于内容。内容与指令的父级具有相同的范围。另请注意,如果定义了模板,则内容将被模板替换。要使用模板以外的内容,需要 "transcluding" (transclude: true)(但是,这超出了此答案的范围)。

如果您感到困惑,您可以随时检查 $scope.$id 以了解适用的范围:

<div>parent scope: {{$id}} (will be 2)</div>

<isolate-scope>
   contents of isolate scope directive: {{$id}} (will also be 2)
</isolate-scope>

<isolate-scope-with-template>
   contents will be replaced with the template
</isolate-scope-with-template>
.directive("isolateScopeWithTemplate", function(){
   return {
     scope: {},
     template: "template: {{$id}} (will NOT be 2)"
   }
})

(当然,实际的$id可能不同)

child scope (scope: true) 指令中,应用于内容的范围实际上与应用于模板的范围相同(此处相同 -模板将替换内容(如果存在,除非您嵌入)。

现在,回答你的问题

第一个 <span ng-bind="test2"></span> 绑定到父作用域中不存在的 $scope.test2,因此它是空的。

但是 isolatedDirectiveNumberTwo 模板中的 <span ng-bind="test2"></span> 绑定到该指令的隔离范围,它定义了 $scope.test2 = 'Binded from directive controller!'.

现在我了解了全貌,正如 New Dev 在他的回答中所述

In isolate scope (scope: {}) directives, the isolate scope applies to the template, but not to the contents. The contents have the same scope as the directive's parent.

所以我了解到指令内容和模板之间存在差异,以及范围是如何在隔离范围上继承的。 对于我的应用程序,将范围设置为 true 完全解决了我的问题。

此外,kwan245 的解决方案是解决此问题的真正好方法。

这两个答案让我头脑清醒,非常感谢 New Dev 和 kwan245 :)