2014-07-23 63 views
0

我遵循这本关于指令的书,并决定在只读范围上尝试他们的代码。但是,我得到奇怪的结果。角度只读范围很奇怪

发生的事情是:

  1. 在开始使用#appTitle应该读的 “Hello World” 和#newDirTitle应该读的 “Hello World的指令”(它doesnt)
  2. #newAppTitle#appTitle用户点击后将改变到App 2.0和#newDirTitle应改为 “应用程序2.0的指令”(它不)
  3. 当点击#newDirTitle,只有该指令的标题必须改变(它doesnt)

我也注意到了下来摆弄角版本1.1.1解决了这个问题。虽然我确实接受一些小的版本更改可能会影响整体行为,但我不明白为什么,例如,案例3停止工作或为什么在案例1中标题仍然读取原始应用标题(“Hello World”)值而不是scoped标题只读值(“Hello World指令”)。谁能解释一下吗?

下面是代码:

HTML

<div ng-app="demoApp"> 
    <div ng-controller="AppController"> 
     <div ng-init="title = 'Hello World'"> 
      <h2 id="appTitle">{{ title }}</h2> 
      <button id="newAppTitle" ng-click="setAppTitle('App 2.0')">Upgrade Me!</button> 
      <div my-scoped-directive="" msd-title="Directive of {{ title }}"> 
       <h4 id="directiveTitle">{{ title }}</h4> 
       <button id="newDirTitle" ng-click="setDirectiveTitle('bob')">Bob it!</button> 
      </div> 
     </div> 
    </div> 
</div> 

JS

var demoApp = angular.module('demoApp', []); 

demoApp.controller("AppController", function($scope) { 
    $scope.setAppTitle = function(t) { 
     $scope.title = t; 
    }; 
}); 

demoApp.directive("myScopedDirective", function() { 
    return { 
     scope: { 
      title: '@msdTitle' 
     }, 
     link: function(scope, element, attrs) { 
      scope.setDirectiveTitle = function(t) { 
       scope.title = t; 
      }; 
     } 
    }; 
}); 

的jsfiddle

Click here to view

回答

1

这本书可能会过时(也许是基于Angular的早期版本)。

有两个错误:

1.在myScopeDirective的分离的范围的 'setDirectiveTitle' 不是从HTML访问:

<div my-scoped-directive="" msd-title="Directive of {{ title }}"> 
     <!--*** THE CONTENTS BELOW THE DIRECTIVE ARE BOUND TO AppController's SCOPE ***--> 
     <h4 id="directiveTitle">{{ title }}</h4> 
     <button id="newDirTitle" ng-click="setDirectiveTitle('bob')">Bob it!</button> 
    </div> 

setDirectiveTitle( '鲍勃')为界到AppController的范围不是指令的隔离范围。在AppController的作用域中,该方法不存在。由于孤立的作用域是“孤立的”,并且不会从父域(AppController的作用域)继承作用域,所以按钮单击事实上并不实际执行任何操作。

。指令下的内容绑定到AppController的作用域 - 而不是隔离的作用域。所以'标题'模型实际上是与它上面的'appTitle'相同的模型。两个标题都说'Hello World'是因为两者都绑定到AppController范围的同一模型'标题'。这也是为什么当第一个按钮被点击时两个标题同时改变为相同标题的原因。

我认为作者犯的主要错误是myScopedDirective下的内容被绑定到隔离范围的错误假设。对Angluar的早期版本来说,这可能是正确的,但对于Angular 1.2及更高版本,这肯定不是真的。内容绑定到父范围(AppController的范围)。

+0

哇哦..这整个作用域业务现在已经完全改变了。所以基本上你所说的是,任何在指令下执行函数的ng-click现在总是绑定到该指令所在的控制器上?那么如何用ng-click来执行指令的功能呢? – AVK

+0

主HTML页面中的指令可以创建从父作用域继承的子作用域,最终创建到$ rootScope。所以说,任何在指令下执行函数的ng单击都绑定到元素的当前作用域(可以被继承,或者它可能是由指令创建的子作用域),这是更正确的。您可以通过在元素当前范围(或任何父范围,因为它继承范围)上定义点击处理程序来执行ng-click。 – pixelbits

+0

要处理指令的隔离范围内的点击事件,您要么绑定到javascript'click'事件(不使用ng-click),要么在您的指令模板中声明一个按钮(不要声明它在主HTML中)。 – pixelbits

1

在Angular中使用范围有时可能会令人困惑。还有一点需要记住的是,“链接”功能与控制器不同,因此可以使用控制器创建指令。如果您在指令中需要自定义功能,则可以使用JQLite绑定(不推荐),或为指令创建控制器。这确实需要你也为你的指令需要的HTML使用模板(这可以用模板内联,或者用templateUrl提取到html)。这是你的指令的更新例子(代码后说明)

demoApp.directive("myScopedDirective", function() { 
    return { 
     template: '<h4 id="directiveTitle">Directive of {{ directiveTitle }}</h4><button id="newDirTitle" ng-click="setDirectiveTitle(\'bob\')">Bob it!</button>', 
     scope: { 
      title: '=msdTitle', 
      directiveTitle: '@msdTitle' 
     }, 
     controller: function($scope){ 
      $scope.setDirectiveTitle = function(t) { 
       $scope.directiveTitle = t; 
      }; 
     }, 
     link: function(scope, element, attrs) { 
      scope.$watch('title', function(){ 
       scope.directiveTitle = scope.title; 
      }); 
     } 
    }; 
}); 

由于您的要求是,当上了父母控制范围标题修改该指令的标题应该藏汉改变,我们基本上需要做的副本标题,但正如你所看到的,我使用@作为标题directiveTitle=。 @将采用标题的初始值,但不会观察属性的更改,而=会随着其分配的属性更改而发生更改,在本例中为AppController.title

在我们的链接功能中,我们现在将原始标题设置为$watch,以确保我们可以在AppController.title更改时保持最新状态。

setDirectiveTitle现在是注入到指令控制器中的作用域,并且更改了directiveTitle属性,该属性再次绑定在我们的模板中。

不确定这是否正是您想要的,但它似乎符合您的要求。 :)

更新小提琴:

http://jsfiddle.net/uH76g/

+1

非常感谢!另一个答案也为我清楚,必须有一个模板,以便指令将其应用于HTML的范围。我很困惑,认为指令开放和结束标记之间的任何内容“属于”指令的范围。但事实证明,这是一种过时的做事方式:) – AVK