Angularjs观察不使用对象内的数组

时间:2016-08-21 22:59:39

标签: javascript angularjs arrays

我有一个对象{Client:[],Employee:[],Product:[],Project:[],PayPeriod:[]},其中每个数组都通过双向绑定被组件推送和拼接。主控制器连接所有5个阵列并将它们分配给另一个组件。在所述组件中,我需要观察绑定,但无论我做什么都不起作用。这就是我现在所拥有的。

$scope.$watch('ctrl.parameters', ctrl.Update(), true);

ctrl.Update();是一个功能和工作 ctrl.parameters确实会更新,但不会触发$ watch。

这有点复杂,所以如果你需要解释黄油,我可以。

ctrl.Update = function () {
        $.post("/TrackIt/Query.php?Type=getViaParams&EntityType="+ctrl.entity,{Params:ctrl.parameters},function(Data,Status){
            if(Status=="success"){
                if (Data.Success) {
                    ctrl.List = Data.Result.Entities;
                } else {
                    AlertService.Alert(Data.Errors[0],false,null);
                    SessionService.Session(function () {
                        ctrl.Update();
                    });
                }
                $scope.$apply();
            }else{
                AlertService.Alert("Something is up with the select options",false,null);
            }
        },'json');
    };

编辑1:
Par = {Client:[],Employee:[],Product:[],Project:[],PayPeriod:[]}
5具有双向绑定的组件= Par.X(这些是编辑参数的内容)
1具有双向绑定的组件= Par(我需要在此处观察绑定)

编辑2:

<script>
    TrackIT.controller('EntryController', function EntryController($scope, $http, AlertService, SessionService, DisplayService) {
        $scope.Parameters = {Client:[],Employee:[],Product:[],Project:[],PayPeriod:[]};
        $scope.Values = {};

    });
</script>
<style>
    entity-select{
        float: left;
        display: inline;
        padding: 0 5px;
    }
    #SelectParameters{
        float: left;
    }
</style>
<div ng-app="TrackIT" ng-controller="EntryController">
    <div id="SelectParameters">
        <entity-select entity="'Client'" ng-model="Values.Client" multi="true" ng-array="Parameters.Client"></entity-select>
        <entity-select entity="'Employee'" ng-model="Values.Employee" multi="true" ng-array="Parameters.Employee"></entity-select>
        <entity-select entity="'Product'" ng-model="Values.Product" multi="true" ng-array="Parameters.Product"></entity-select>
        <entity-select entity="'Project'" ng-model="Values.Project" multi="true" ng-array="Parameters.Project"></entity-select>
        <entity-select entity="'PayPeriod'" ng-model="Values.PayPeriod" multi="true" ng-array="Parameters.PayPeriod"></entity-select>
    </div>
    <br>
    <parameter-table entity="'Entry'" parameters="Parameters"></parameter-table>
</div>

TrackIT.component('entitySelect', {
templateUrl: "/Content/Templates/Select.html",
controller: function SelectController($scope, $http, AlertService, SessionService) {
    var ctrl = this;
    ctrl.Options = [];
    ctrl.Display = [];

    ctrl.Add = function () {
        var Display = {'Label':ctrl.Label(ctrl.ngModel),'Value':ctrl.ngModel};
        ctrl.ngArray.push(ctrl.ngModel);
        ctrl.Display.push(Display);
    };

    ctrl.Remove = function (Key) {
        ctrl.ngArray.splice(Key, 1);
        ctrl.Display.splice(Key, 1);
    };

    ctrl.$onInit = function() {
        $.post("/TrackIt/Query.php?Type=getSelectList&EntityType="+ctrl.entity,null,function(Data,Status){
            if(Status=="success"){
                if (Data.Success) {
                    ctrl.Options = Data.Result.Entities;
                    if(ctrl.ngModel==undefined){
                        if(ctrl.none){
                            ctrl.ngModel = "NULL"
                        }else{
                            ctrl.ngModel = angular.copy(ctrl.Options[0].Attributes.ID.Value.toString());
                        }
                    }
                } else {
                    AlertService.Alert(Data.Errors[0],false,null);
                }
                $scope.$apply();
            }else{
                AlertService.Alert("Something is up with the select options",false,null);
            }
        },'json');
    };

    ctrl.Label = function(Value) {
        for (var prop in ctrl.Options) {
            if(!ctrl.Options.hasOwnProperty(prop)) continue;
            if(ctrl.Options[prop].Attributes.ID.Value.toString()==Value.toString()){
                return ctrl.Options[prop].DisplayName;
            }
        }
    };

},
bindings: {
    entity:"<",
    multi:"<",
    none:"<",
    ngModel:"=",
    ngArray:"="
}
});

TrackIT.component('parameterTable', {
templateUrl: "/Content/Templates/BasicTable.html",
controller: function ParameterTableController($scope, $http, AlertService, SessionService, DisplayService) {
    var ctrl = this;
    ctrl.List = {};

    ctrl.Update = function () {
        $.post("/TrackIt/Query.php?Type=getViaParams&EntityType="+ctrl.entity,{Params:ctrl.parameters},function(Data,Status){
            if(Status=="success"){
                if (Data.Success) {
                    ctrl.List = Data.Result.Entities;
                } else {
                    AlertService.Alert(Data.Errors[0],false,null);
                    SessionService.Session(function () {
                        ctrl.Update();
                    });
                }
                $scope.$apply();
            }else{
                AlertService.Alert("Something is up with the select options",false,null);
            }
        },'json');
    };

    $scope.$watch('ctrl.parameters', ctrl.Update.bind(ctrl), true);

    ctrl.$onInit = function() {
        DisplayService.DisplayTrigger(function () {
            ctrl.Update();
        });
        ctrl.Update();
    }
},
bindings: {
    entity: "<",
    parameters: "="
}
});

2 个答案:

答案 0 :(得分:3)

这里有两个问题。

问题1:ctrl不是范围

上的属性

在看到完整的控制器代码后,我可以看到ctrl只是this的别名,$ctrl是控制器的实例,默认情况下将作为$scope.$watch()在范围内发布。但是你可以通过将函数而不是字符串传递给// ES5 $scope.$watch(function () { return ctrl.parameters; }, ctrl.Update, true); // ES6/Typescript/Babel $scope.$watch(() => ctrl.parameters, ctrl.Update, true); 来避免担心调用它的内容:

$scope.$watch()

这是Angular的所有功能

你可能没有意识到,就Angular而言,它总是为每个手表调用一个函数来获取要比较的值。将字符串传递给$parse时,Angular使用$scope.$watch()从该表达式创建函数。这就是Angular如何将字符串转换为绑定,表达式等中的可执行代码。

创建的函数接受一个参数,这是评估表达式的“上下文”。您可以将其视为要使用的范围。

当您将函数传递给ctrl.Update()作为第一个参数时,您可以有效地保存Angular必须从字符串中为您创建函数。

问题2:指定监听侦听器功能的方式

ctrl.parameters函数只是您希望$scope.$watch('ctrl.parameters', ctrl.Update(), true);更改时运行的函数。

您在ctrl.parameters的代码中所说的是:

  

ctrl.Update()上进行深入监视(观察对任何属性的更改),当它发生更改时,调用调用ctrl.Update的结果,这将是一个jQuery承诺,而不是函数。

相反,您希望将$scope.$watch()函数本身作为第二个参数传递给ctrl.Update,因此在检测到更改时会调用它。要做到这一点,只需传递ctrl.Update()而不是$scope.$watch('ctrl.parameters', ctrl.Update, true);

ctrl.Update

注意事项

在这种特殊情况下使用this将起作用,因为在该函数中没有使用this。对于查看此答案的其他人,请注意,当您以这种方式传递函数时,ctrl绑定(“上下文”)不会像您预期的那样维护为ctrl.Update.bind(ctrl)。要解决此问题,请使用$scope.$watch('ctrl.parameters', function () { ctrl.Update() }, true);,或者将其包装在函数中,以便使用正确的上下文调用它:{{1}}。

谨慎使用深度/价值手表

你应该非常谨慎地使用Angular应用程序中的深度手表(也称为超值手表)。原因是对于大对象来说这是一个非常昂贵的操作,因为Angular必须在每个摘要周期中对对象进行深度比较 - 遍历整个对象上的每个属性,然后,如果有变化,则制作对象的深度克隆,再次需要遍历每个属性以制作完全独立的副本,以便与下次进行比较。

您可以考虑对具有 n 属性的对象进行深入监视,因为它等同于 n 浅/参考监视。

我觉得你的情况可能是一个非常大的数字。

答案 1 :(得分:0)

我认为问题是你的监视声明不正确。 $ watch的第二个参数必须是一个函数。以下应该有效:

$scope.$watch('ctrl.parameters', ctrl.Update.bind(ctrl), true);

请注意使用bind确保this参数设置正确。