Angular指令父范围

时间:2016-08-21 11:34:44

标签: javascript jquery angularjs angularjs-directive angularjs-scope

我正在构建一个装饰表头项目的指令,并在click事件中对数据进行排序。我无法使用指令范围将数据模型上的更改应用于父作用域。

vm.data是父作用域上的一个数组,它包含我要在指令中排序的数据。 单击后,指令中的数据对象已更改,但父级仍处于相同的顺序。

我不想使用$ parent访问父作用域,我错过了什么?

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

指令代码:

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

2 个答案:

答案 0 :(得分:0)

这是因为你正在使用jQuery来监听元素的变化。所以只需改变这一行:

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

element.on("click", sort);

如果jQuery不可用,第二个属性即element已经是jQlite的一个实例,如果jQuery可用,它将是jQuery的一个实例。

在任何情况下,都有一个可用的方法.on,它将在值更改时执行。由于您再次将其包装到$(),因此Angular未收到有关数据更改的通知。

编辑:

在第二次浏览代码时,我看到了实际问题。您正在重新分配scope.data方法中的完整sort(),该方法违反了Javascript(或任何OOPS编程)的引用行为。

通过引用传递仅在您继续修改 SAME 引用变量时才有效。注意到这个词,相同?通过编写scope.data = lodash.sortBy(scope.data, function (o) {}),您删除了传递给指令的实际数据的引用。因此,值不会更新。

所以要解决这个问题,你有几个选择:

  1. 更改您的排序代码,以便不重新分配完整的scope.data变量推荐(使用内置sort方法)
  2. 使用data
  3. 将修改后的scope.$emit()传递给父作用域
  4. 或使用您不想使用的$parent媒体资源

答案 1 :(得分:0)

双向绑定更新每个摘要周期的父级,但点击处理程序需要使用$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';
            }

        }

ng-click指令自动调用$apply但是当AngularJS jqLite处理click事件时,代码需要通知AngularJS框架。

来自文档:

  

$apply([exp]);

     

$apply()用于从角度框架外部以角度执行表达式。 (例如,来自浏览器DOM事件,setTimeout,XHR或第三方库)。因为我们正在调用角度框架,所以我们需要执行exception handlingexecuting watches的适当范围生命周期。

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