Javascript Angularjs watch无法处理对象内部的数组

Javascript Angularjs watch无法处理对象内部的数组,javascript,angularjs,arrays,Javascript,Angularjs,Arrays,我有一个对象{Client:[]、Employee:[]、Product:[]、Project:[]、PayPeriod:[]},其中每个数组都由组件通过双向绑定推送和拼接。主控制器连接所有5个阵列,并将它们提供给另一个组件。在上述组件中,我需要观察绑定,但无论我做什么,它都不起作用。这就是我现在拥有的 $scope.$watch('ctrl.parameters', ctrl.Update(), true); ctrl.Update();是一个函数,可以工作。 ctrl.parameters

我有一个对象<代码>{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={客户:[],员工:[],产品:[],项目:[],付款期:[]}

5个具有双向绑定的组件= PAR.X(这些是编辑参数)BR> 具有双向绑定的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: "="
}
});

controller('EntryController',函数EntryController($scope,$http,AlertService,SessionService,DisplayService){
$scope.Parameters={客户:[],员工:[],产品:[],项目:[],付款期:[]};
$scope.Values={};
});
实体选择{
浮动:左;
显示:内联;
填充:0 5px;
}
#选择参数{
浮动:左;
}

TrackIT.component('entitySelect'{ templateUrl:“/Content/Templates/Select.html”, 控制器:函数SelectController($scope、$http、AlertService、SessionService){ var ctrl=this; ctrl.Options=[]; ctrl.Display=[]; ctrl.Add=函数(){ 变量显示={'Label':ctrl.Label(ctrl.ngModel),'Value':ctrl.ngModel}; ctrl.ngArray.push(ctrl.ngModel); ctrl.Display.push(显示); }; ctrl.Remove=功能(键){ ctrl.ngArray.splice(键1); ctrl.Display.splice(键1); }; ctrl.$onInit=函数(){ $.post(“/TrackIt/Query.php?Type=getSelectList&EntityType=“+ctrl.entity,null,函数(数据,状态){ 如果(状态=“成功”){ if(Data.Success){ ctrl.Options=Data.Result.Entities; if(ctrl.ngModel==未定义){ 如果(ctrl.none){ ctrl.ngModel=“NULL” }否则{ ctrl.ngModel=angular.copy(ctrl.Options[0].Attributes.ID.Value.toString()); } } }否则{ AlertService.Alert(Data.Errors[0],false,null); } $scope.$apply(); }否则{ AlertService.Alert(“选择选项有问题”,false,null); } }“json”); }; ctrl.Label=函数(值){ 用于(ctrl.Options中的var prop){ 如果(!ctrl.Options.hasOwnProperty(prop))继续; 如果(ctrl.Options[prop].Attributes.ID.Value.toString()==Value.toString()){ 返回ctrl.Options[prop].DisplayName; } } }; }, 绑定:{
实体:“这里有两个问题

问题1:
ctrl
不是作用域上的属性 在看到完整的控制器代码后,我可以看到
ctrl
只是
this
的别名,默认情况下,该控制器的实例将以
$ctrl
的形式发布在作用域上。但是,通过将函数而不是字符串传递到
$scope.$watch()

所有的函数都是有角度的 您可能不知道,就Angular而言,它总是为每个手表调用一个函数以获取要比较的值
,Angular使用
$parse
从该表达式创建函数。这就是Angular如何将字符串转换为绑定、表达式等中的可执行代码

创建的函数只包含一个参数,该参数是计算表达式的“上下文”。您可以将其视为要使用的范围

当您将函数作为第一个参数传递给
$scope.$watch()
时,可以有效地节省从字符串创建函数的时间

问题2:指定监视侦听器函数的方式 您的
ctrl.Update()
函数只是希望在
ctrl.parameters
发生更改时运行的函数

您在
$scope.$watch('ctrl.parameters',ctrl.Update(),true);
的代码中所说的是:

ctrl.parameters
执行深度监视(监视对任何属性的更改),当它更改时,调用调用
ctrl.Update()
的结果,这将是一个jQuery承诺,而不是一个函数

相反,您希望将
ctrl.Update
函数本身作为第二个参数传递给
$scope.$watch()
,以便在检测到更改时调用它。为此,只需传递
ctrl.Update
而不是
ctrl.Update()

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

谨慎使用深度/价值表 在Angular应用程序(也称为value watches)中使用deep watches时,你应该非常谨慎。原因是,对于大型对象来说,这是一个非常昂贵的操作,因为Angular必须在每个摘要循环中对对象进行深入比较-遍历
// ES5
$scope.$watch(function () { return ctrl.parameters; }, ctrl.Update, true);
// ES6/Typescript/Babel
$scope.$watch(() => ctrl.parameters, ctrl.Update, true);
$scope.$watch('ctrl.parameters', ctrl.Update, true);
$scope.$watch('ctrl.parameters', ctrl.Update.bind(ctrl), true);