如何在AngularJS指令中修改作用域(scope)?

26

我需要在指令的回调函数内修改一个根作用域属性。但是,这个指令是在由switch指令创建的内部作用域中。

HTML

<div ng-app="app" ng-controller='AppController'>
    <p>Selected: {{ selected }}</p>
    <div ng-switch on="selected">
        <div ng-switch-default>
            <p>Item: {{ selected }}</p>
            <custom-tag selected-item="selected" />
        </div>
        <div ng-switch-when="New value">
            <p>Worked</p>
        </div>
    </div>
</div>

JavaScript

angular.module('app', [])    
    .directive("customTag", [function () {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='button' value='Click me' />",

        link: function (scope, element, attrs) {
            element.bind('click', function () {
                scope[attrs.selectedItem] = "New value";
                scope.$apply();
            });
        }
    };
}]);

function AppController($scope) {
    $scope.selected = 'Old value';
}

Fiddle: http://jsfiddle.net/nJ7FQ/

我的目标是能够在选择区域显示“New value”。 我应该如何实现我的目标?我做错了什么? 此外,由于我正在尝试制作一个组件。有没有一种方法可以使用隔离作用域来完成相同的操作?

2个回答

20
我更新了fiddle,基本上必须去到父级才能获取正确的"selected"变量,并使用隔离作用域=来在传递的值和内部模型之间进行双向绑定。 http://jsfiddle.net/nJ7FQ/2/
angular.module('app', [])

    .directive("customTag", [function () {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='button' value='Click me' />",
        scope: {model:'='},

        link: function (scope, element, attrs) {
            element.bind('click', function () {
                scope.model[attrs.selectedItem] = "New value";
                scope.$apply();
            });
        }
    };
}]);

function AppController($scope) {
    $scope.selected = 'Old value';
}

以及 HTML

<div ng-app="app" ng-controller='AppController'>
    <p>Selected: {{ selected }}</p>
    <div ng-switch on="selected">
        <div ng-switch-default>
            <p>Item: {{ selected }}</p>
            <custom-tag selected-item="selected" model="$parent" />
        </div>
        <div ng-switch-when="New value">
            <p>Worked</p>
        </div>
    </div>
</div>

更新了示例,使用属性中的原始读取方式来读取该属性的值: http://jsfiddle.net/nJ7FQ/4/


我更喜欢你的第一个解决方案(http://jsfiddle.net/nJ7FQ/2/)。它看起来更加简洁。但是,从我的理解来看,为什么我应该使用$parent.selected,因为子作用域继承父作用域的所有属性? - Fernando
1
如果您更改所继承的选定内容,则不会更改父范围的选定变量。相反,应该到父级并更改该作用域上的变量,然后当读取子选定值时,它会向上到父级。如果您更改子作用域的选定属性,则它将成为子作用域上的新属性,不再继承(我知道这很令人困惑)。如果您想了解更多信息,请搜索JavaScript原型继承。 - shaunhusain
这个不起作用。在指令中设置 scope:'=' 会使 scope 未定义。 - dopatraman
@dopatraman,是的,在过去的一年里,我对Angular有了更多的了解,我不再同意我自己在这里的答案,但我不确定你遇到的问题是否与我对这种方法的问题有关。如果你在Stack Overflow上发布了另一个问题,并附上你的代码和问题链接,请在这里提供链接,我会帮你看一下。 - shaunhusain
请注意,必须使用 link这个替代方案与 shaunhusain 的完全相同,只是使用了 controller,但不起作用。可能是因为隔离作用域仅在 link 函数设置时才设置好,而不是在 controller 函数中。 - Nate Anderson

15

我稍微改进了这个jsfiddle:

angular.module('app', [])

    .directive("customTag", ['$parse', function ($parse) {
    return {
        restrict: "E",
        replace: true,
        template: "<input type='button' value='Click me' />",

        link: function (scope, element, attrs) {
            element.bind('click', function () {
                scope.$apply(function () {
                    $parse(attrs.selectedItem).assign(scope.$parent, "New value");
                });
            });
        }
    };
}]);

function AppController($scope) {
    $scope.selected = { 'foo': 'Old value' };
}

http://jsfiddle.net/nJ7FQ/15/

这样,您想要更改的作用域值也可以是对象属性,例如示例中的selected.foo。此外,我删除了作用域参数,并告诉指令始终使用父作用域。最后,我将单击处理程序包装到$apply回调中(例如,请参见here)。当然,最好使用ngClick而不是element.bind()

BINGO!很好的解决方案来分配父级作用域。非常适合像模态框这样的东西。 - saike

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接