我有一个对象{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: "="
}
});
答案 0 :(得分:3)
这里有两个问题。
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而言,它总是为每个手表调用一个函数来获取要比较的值。将字符串传递给$parse
时,Angular使用$scope.$watch()
从该表达式创建函数。这就是Angular如何将字符串转换为绑定,表达式等中的可执行代码。
创建的函数接受一个参数,这是评估表达式的“上下文”。您可以将其视为要使用的范围。
当您将函数传递给ctrl.Update()
作为第一个参数时,您可以有效地保存Angular必须从字符串中为您创建函数。
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
参数设置正确。