Angular只读范围很奇怪

时间:2014-07-23 05:29:20

标签: javascript angularjs angularjs-directive

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

应该发生的事情是:

  1. 一开始, #appTitle 应该读取" Hello World"并且 #newDirTitle 应该读取" Hello World的指令" (它没有)
  2. 用户点击 #newTitle 后, #appTitle 会更改为App 2.0, #newDirTitle 应该会读取" App指令2.0" (它没有)
  3. 点击 #newDirTitle 时,只有指令的标题必须更改(不是)
  4. 我还注意到,摆弄角度版本降至1.1.1解决了这个问题。虽然我接受一些小的版本更改可能会影响整体行为,但我不明白为什么,例如,案例3停止工作或为什么在案例1中标题仍然读取原始应用程序标题(" Hello World" )值而不是作用域标题只读值(" 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

2 个答案:

答案 0 :(得分:1)

这本书可能已经过时(可能是基于早期版本的Angular)。

有两件事是错的:

1。无法从HTML访问myScopeDirective隔离范围内的'setDirectiveTitle':

    <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')绑定到AppController的范围而不是指令的隔离范围。在AppController的范围内,该方法不存在。由于隔离范围是“隔离的”并且不从父(AppController的范围)继承范围,因此按钮单击实际上不会执行任何操作。

<强> 2 即可。指令下的内容绑定到AppController的范围 - 而不是孤立的范围。所以'title'模型实际上与它上面的'appTitle'模型相同。两个标题都说“Hello World”的原因是因为它们都与AppController范围内的同一模型“标题”绑定。这也是为什么当单击第一个按钮时,两个标题同时更改为同一标题的原因。

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

答案 1 :(得分: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/

相关问题