[英]Angularjs watch not working with array inside of object
我有一個對象{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: "="
}
});
這里有兩個問題。
ctrl
不是作用域上的屬性 看完完整的控制器代碼后,我可以看到ctrl
只是this
的別名,默認情況下,控制器的實例將在$ctrl
Scope上發布到作用域中。 但是您可以不必擔心調用什么,只需將函數而不是字符串傳遞給$scope.$watch()
:
// ES5
$scope.$watch(function () { return ctrl.parameters; }, ctrl.Update, true);
// ES6/Typescript/Babel
$scope.$watch(() => ctrl.parameters, ctrl.Update, true);
您可能並不知道,就Angular而言,它總是為每個手表調用一個函數以獲取要比較的值。 當您將字符串傳遞給$scope.$watch()
,Angular將使用$parse
從該表達式創建函數。 這就是Angular將字符串轉換為綁定,表達式等中的可執行代碼的方式。
創建的函數采用單個參數,即用於評估表達式的“上下文”。 您可以將其視為要使用的范圍。
當您將函數作為第一個參數傳遞給$scope.$watch()
,可以有效地節省Angular不得不從字符串中為您創建函數的麻煩。
ctrl.Update()
函數只是要在ctrl.parameters
更改時運行的函數。
您在$scope.$watch('ctrl.parameters', ctrl.Update(), true);
代碼中所說的內容$scope.$watch('ctrl.parameters', ctrl.Update(), true);
是:
對
ctrl.parameters
進行深入監視(監視任何屬性的更改),並在更改時,調用ctrl.Update()
的結果,這將是jQuery的承諾,而不是函數。
相反,您想將ctrl.Update
函數本身作為第二個參數傳遞給$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);
。
在Angular應用程序中使用深表(也稱為超值手表)時,您應該非常謹慎。 原因是對於大型對象而言這是一個非常昂貴的操作,因為Angular必須在每個摘要循環中對對象進行深入的比較-遍歷整個對象的每個屬性,然后進行更改(如果有更改)對象的深層克隆,這再次需要遍歷每個單個屬性以制作完全獨立的副本以與下一次進行比較。
您可以將對具有n個屬性的對象的深度監視視為等同於n個淺表/參考監視。
我覺得在您的情況下人數可能很多。
我認為問題在於您的監視語句不正確。 $ watch的第二個參數必須是一個函數。 以下應該工作:
$scope.$watch('ctrl.parameters', ctrl.Update.bind(ctrl), true);
請注意使用bind
來確保正確設置this
參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.