简体   繁体   English

Angular指令父范围

[英]Angular directive parent scope

I'm building a directive that decorates a table header item and sort the data upon the click event. 我正在建立一个装饰表标题项并在click事件后对数据进行排序的指令。 I cannot apply the changes on the data model to the parent scope using the directive scope. 我无法使用指令范围将数据模型上的更改应用于父范围。

vm.data is an array on the parent scope that contains the data I want to sort in the directive. vm.data是父作用域上的一个数组,其中包含我要在指令中排序的数据。 After the click the data object in the directive has changed but the parent is still in the same order. 单击后,指令中的数据对象已更改,但父对象仍处于相同顺序。

I dont want to access the parent scope using $parent, What I'm missing ?? 我不想使用$ parent访问父范围,我想念的是什么?

<th sortable="browser" data="vm.data">Browser</th>

directive code: 指令代码:

angular
    .module("app")
    .directive("sortable", ['lodash', sortableDirective]);

function sortableDirective(lodash) {
    return {
        restrict: "A",
        scope:{
            data:"="
        },
        controller:function($scope){

        },
        link: function (scope, element, attributes) {

            var sorted = undefined;
            var col = attributes['sortable'];
            var oldClass = 'sorting'

            attributes.$$element.addClass(oldClass);
            $(element).on("click", sort);

            function changeClass(){
                if(sorted=='asc'){
                    attributes.$$element.removeClass(oldClass);
                    attributes.$$element.addClass('sorting_asc');
                    oldClass = 'sorting_asc';
                }
                else if(sorted=='desc'){
                    attributes.$$element.removeClass(oldClass);
                    attributes.$$element.addClass('sorting_desc');
                    oldClass='sorting_desc';
                }

            }

            function sort() {

                if (sorted == 'asc') {
                    sorted = 'desc';
                }
                else {
                    sorted = 'asc';
                }

                scope.data = lodash.sortBy(scope.data, function (o) {
                    return o[col];
                });

                if (sorted == 'desc') {
                    lodash.reverse(scope.data);
                }

                changeClass();
            }
        }
    };
}

This is because you are using jQuery to listen to change on the element. 这是因为您正在使用jQuery来侦听元素上的更改。 So just change this line: 因此,只需更改此行:

$(element).on("click", sort);

to

element.on("click", sort);

The 2nd attribute ie element is already an instance of jQlite if jQuery is not available and will be an instance of jQuery if jQuery is available. 如果jQuery不可用,第二个属性ie element已经是jQlite的实例,如果jQuery可用,它将是jQuery的实例。

In any case, there is a method available .on which will be executed on the value change. 在任何情况下,有一种方法可用.on其中将在值变化来执行。 Since you again wrapped it to $() , the Angular was not getting notified of the change in the data. 由于您再次将其包装到$() ,因此Angular尚未收到有关数据更改的通知。

Edit: 编辑:

On the 2nd walk through of your code, I see the actual problem. 在您的代码的第二遍中,我看到了实际的问题。 You are reassigning the complete scope.data in the sort() method which is breaking the pass by reference behavior of Javascript (or in any OOPS programming). 您正在sort()方法中重新分配完整的scope.data ,这会破坏Javascript(或任何OOPS编程)的引用行为。

The pass by reference will only work if you continue to modify your SAME reference variable. 仅当您继续修改SAME参考变量时,按引用传递才有效。 Noticed the word, SAME ?? 注意到这个词, SAME ?? By writing scope.data = lodash.sortBy(scope.data, function (o) {}) you removed the reference of the actual data passed to the directive. 通过编写scope.data = lodash.sortBy(scope.data, function (o) {})您删除了传递给指令的实际数据的引用。 Hence the values are not updated. 因此,值不会更新。

So to fix this problem, you have a few options: 因此,要解决此问题,您有几种选择:

  1. Change your sorting code to not reassign the complete scope.data variable RECOMMENDED (use inbuilt sort method) 更改排序代码以不重新分配完整的scope.data变量RECOMMENDED (使用内置sort方法)
  2. Pass the modified data to the parent scope using scope.$emit() 使用scope.$emit()将修改后的data传递到父范围
  3. Or use the $parent property which you don't want to use 或使用您不想使用的$parent属性

The bidirectional binding will update the parent on each digest cycle but the click handler needs to invoke that digest cycle with $apply : 双向绑定在每个摘要循环上更新父级,但单击处理程序需要使用$apply调用该摘要循环:

    link: function (scope, element, attributes) {

        var sorted = undefined;
        var col = attributes['sortable'];
        var oldClass = 'sorting'

        element.addClass(oldClass);

        //REPLACE this
        //$(element).on("click", sort);
        //
        //WITH this           
        element.on("click", function (e) {
            sort();
            scope.$apply();
        });

        function changeClass(){
            if(sorted=='asc'){
                element.removeClass(oldClass);
                element.addClass('sorting_asc');
                oldClass = 'sorting_asc';
            }
            else if(sorted=='desc'){
                element.removeClass(oldClass);
                element.addClass('sorting_desc');
                oldClass='sorting_desc';
            }

        }

The ng-click directive automatically invokes $apply but when the click event is handled by AngularJS jqLite , the code needs to notify the AngularJS framework. ng-click指令自动调用$apply但是当AngularJS jqLit​​e处理click事件时,代码需要通知AngularJS框架。

From the Docs: 从文档中:

$apply([exp]);

$apply() is used to execute an expression in angular from outside of the angular framework. $apply()用于从角度框架外部以角度执行表达式。 (For example from browser DOM events, setTimeout, XHR or third party libraries). (例如,来自浏览器DOM事件,setTimeout,XHR或第三方库)。 Because we are calling into the angular framework we need to perform proper scope life cycle of exception handling , executing watches . 因为我们正在调用有角度的框架,所以我们需要执行异常处理的适当范围生命周期,并执行监视

-- AngularJS $rootScope.scope API Reference -- $apply -AngularJS $ rootScope.scope API参考-$ apply

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

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