将更改应用于由范围提取的angular.js中的模型。$ ​​apply

时间:2013-07-31 19:38:16

标签: javascript angularjs

我在AngularJS中有一个指令,它可以像这样获取一个数组:

var current_element_list = scope.$apply($(this).attr('sortable-model'));

代码的其余部分如下所示:

//in the controller
$scope.project.elements = [];

//in the html
<customDirective sortable-model='project.elements'>

我认为范围。$ apply会返回对$scope.project.elements数组的引用,因此我在指令中所做的任何更改都将保留在该模型中。但是,似乎并非如此,因为我对数组所做的任何更改都不会保存。无论如何我可以通过sortable-model属性将更改保存到根域中的数组中吗?

3 个答案:

答案 0 :(得分:1)

如果需要指令和控制器作用域之间的双向绑定,则在定义指令时应使用scope属性。

var app = angular.module("app", []);

app.controller("Ctrl", function ($scope) {
    $scope.project = {
        elements: [1, 2, 3]
    };
});

app.directive("customDirective", function () {
    return {
        restrict: "E",
        scope: {
            sortableModel: "="
        },
        link: function (scope, element, attrs) {
            // Access the controller's scope.project.elements here as scope.sortableModel
            console.log(scope.sortableModel);

            // Changes to scope.sortableModel will also affect the controller's scope.project.elements
            scope.sortableModel.push(4);
        }
    };
});

查看working fiddle in action

答案 1 :(得分:1)

您需要设置隔离范围并将模型值映射到指令中的本地。

来自Angularjs指令范围文档:

  

= or = attr - 在本地范围属性和通过attr属性的值定义的name的父范围属性之间设置双向绑定。如果未指定attr名称,则假定属性名称与本地名称相同。范围的给定和窗口小部件定义:{localModel:'= myAttr'},然后窗口小部件范围属性localModel将反映父范围上的parentModel的值。对parentModel的任何更改都将反映在localModel中,localModel中的任何更改都将反映在parentModel中。

angular("app")
  .directive('customDirective ', function () {
   return {
       restrict: 'E',
       link: function (scope, element, attrs) {
           scope.localModel.push("New Element");
       }, 
       scope:{
           localModel: '=sortableModel',
       }
   }
});

答案 2 :(得分:1)

回答你的问题

由于标准原型继承规则适用,因此对指令中数组的更改应反映在原始文件中。执行此操作时,指令中的含义(即使它创建了新范围):

current_element_list[0] = 'new value';

该更改应反映在控制器的$scope.project.elements变量中。

现在如果你的指令没有创建新范围,传递给指令的scope变量应该与包含控制器的$scope相同,这意味着你应该只是能够随意更改该范围内的任何内容。所以如果你在指令中这样做:

scope.project.elements = ['new value'];

该更改也应反映在控制器的$scope.project.elements变量中。

如果您的指令创建了隔离范围,那么您不应该使用scope.$apply($(this).attr('sortable-model'))来获取属性的评估值。相反,您将使用:

scope : {
    current_element_list : '=sortableModel'
}

这会创建一个双向数据绑定到sortableModel的评估值,现在可以通过scope.current_element_list访问您的指令。


建议改进代码

关于这一行:

var current_element_list = scope.$apply($(this).attr('sortable-model'));

如果您只想“获取”数组,则无需使用$apply,而是使用$eval$apply函数主要用于将一个函数带回AngularJS上下文,触发摘要循环并检查所有模型是否均衡并且所有更改都被考虑在内。 $eval$apply函数调用)只是评估给定范围内的给定表达式。

此外,使用指令,您不必使用jQuery来获取属性名称或值,甚至是元素本身。链接函数传递4个参数,其中一个是具有所述元素的属性和属性值的对象。指令的控制器也可以注入$ attrs服务,这将返回相同的东西。 (read directive documentation)

以上代码重做:

link : function(scope, element, attrs, controllers) {
    // ...
    var current_element_list = scope.$eval(attrs['sortable-model']);
    // ...
}