简体   繁体   English

角度只读作用域行为很奇怪

[英]Angular read-only scope acts weird

Im following this book on directives and decided to try their code on read-only scopes. 我遵循这本关于指令的书,并决定在只读作用域上尝试其代码。 However, im getting weird results. 但是,即时通讯结果很奇怪。

What should happen is: 应该发生的是:

  1. At the beginning the #appTitle should read "Hello World" and the #newDirTitle should read "Directive of Hello World" (it doesnt) 开始时, #appTitle应该显示为“ Hello World”,而#newDirTitle应该显示为“ Hello World的指令”(不是)
  2. After user clicks on #newAppTitle , #appTitle would change to App 2.0 and #newDirTitle should read "Directive of App 2.0" (it doesnt) 用户单击#newAppTitle之后#appTitle将更改为App 2.0,并且#newDirTitle应该显示为“ App 2.0指令”(不是)
  3. When #newDirTitle is clicked, only the directive's title must change (it doesnt) 单击#newDirTitle时 ,仅伪指令的标题必须更改(不更改)

I've also noticed that fiddling angular version down to 1.1.1 solves the issue. 我还注意到,将角度版本调整为1.1.1可以解决此问题。 While I do accept that some minor version changes might affect the overall behavior, i dont understand why, for instance, case 3 stopped working or why in case 1 the title still reads the original app title ("Hello World") value instead of scoped title read-only value ("Directive of Hello World"). 虽然我确实接受一些小的版本更改可能会影响整体行为,但是我不明白为什么例如案例3停止工作,或者为什么在案例1中标题仍读取原始应用程序标题(“ Hello World”)值而不是范围标题只读值(“ Hello World指令”)。 Could anyone please explain? 有人可以解释吗?

Below is the code: 下面是代码:

HTML 的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 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 JSFIDDLE

Click here to view 点击这里查看

The book may be out-dated (perhaps based on an early version of Angular). 这本书可能已过时(也许基于Angular的早期版本)。

There are two things wrong: 有两件事是错误的:

1. The 'setDirectiveTitle' in the isolated scope of myScopeDirective is not accessible from the HTML: 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('bob') is bound to AppController's scope not the directive's isolated scope. setDirectiveTitle('bob')绑定到AppController的范围,而不是指令的隔离范围。 In AppController's scope, the method doesn't exist. 在AppController的范围内,该方法不存在。 And since isolated scopes are "isolated" and do not inherit scope from the parent (AppController's scope), the button click doesn't actually do anything. 而且,由于隔离范围是“隔离的”并且不会从父级继承范围(AppController的范围),因此单击按钮实际上不会执行任何操作。

2 . 2 The contents under the directive are bound to AppController's scope - not the isolated scope. 指令下的内容绑定到AppController的范围-而不是孤立的范围。 So the 'title' model is actually the same model as the 'appTitle' above it. 因此,“标题”模型实际上与其上方的“ appTitle”模型相同。 The reason why both title's say 'Hello World' is because both are bound to the same model 'title' on AppController's scope. 两个标题都说“ Hello World”的原因是因为两个标题都绑定到AppController范围内的同一模型“ title”。 This is also the reason why both title's change to the same title at the same time when the first button is clicked. 这也是单击第一个按钮时两个标题同时更改为相同标题的原因。

I think the main mistake that the author makes is the incorrect assumption that the contents under myScopedDirective are bound to the isolated scope. 我认为作者犯的主要错误是不正确的假设,即myScopedDirective下的内容绑定到隔离的范围。 This may have been true for earlier versions of Angluar, but it is certainly not true for Angular 1.2 and above. 对于早期版本的Angluar可能是这样,但对于Angular 1.2及更高版本肯定不是这样。 The contents are bound to the parent scope (AppController's scope). 内容绑定到父作用域(AppController的作用域)。

Working with scopes in Angular can be quite confusing at times. 有时在Angular中使用范围可能会造成混乱。 What's also important to remember is that the "Link"-function is not the same as a controller, and that's why Directives can be created using a controller. 还需要记住的重要一点是,“链接”功能与控制器不同,这就是为什么可以使用控制器创建指令的原因。 If you require custom functionality in your directive, you can either bind stuff using JQLite (not recommended), or create a controller for your directive. 如果您在指令中需要自定义功能,则可以使用JQLite绑定内容(不推荐),也可以为指令创建控制器。 This does require that you also use a template for the HTML that your directive needs (and this can be inlined with template, or extracted to html with templateUrl). 这确实要求您还为指令所需要的HTML使用模板(可以使用模板内联,也可以使用templateUrl将其提取为html)。 Here's an updated example of your directive (more explanation after the code) 这是指令的更新示例(代码后有更多说明)

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;
            });
        }
    };
});

Since your requirement was that when the title changes on the parent controller scope the directive title should change aswell, we essentially need to make a copy of the title, but as you see, I use the @ for the directiveTitle and = for the title. 由于您的要求是当标题在父控制器作用域上更改时,指令标题也应同时更改,因此我们基本上需要复制标题,但是如您所见,我对directiveTitle标题使用@ ,对标题使用= The @ will take the initial value of the title, but wont watch the property for changes, whereas the = will change whenever its assigned property changes, in this case the AppController.title . @将采用标题的初始值,但不会监视属性的更改,而=会在其分配的属性发生更改时更改,在本例中为AppController.title

In our Link-function we now set a $watch on the original title, to make sure we can stay up to date when the AppController.title changes. 在链接功能中,我们现在在原始标题上设置了一个$watch ,以确保在AppController.title更改时我们可以保持最新。

The setDirectiveTitle is now a function on the scope injected into the directives controller, and changes the directiveTitle property which again is bound in our template. setDirectiveTitle现在是注入到指令控制器中的作用域上的函数,并更改了又在我们的模板中绑定的directiveTitle属性。

Not sure if this is exactly what you wanted, but it seems to fit your requirements. 不知道这是否正是您想要的,但似乎符合您的要求。 :) :)

Updated fiddle: 更新的小提琴:

http://jsfiddle.net/uH76g/ http://jsfiddle.net/uH76g/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM