观察集合吞噬正在观察的属性
观察集合吞噬正在观察的属性
有两个属性selCountry
和searchText
。有一个监视器来监视这两个变量。第一个属性绑定到一个选择元素,另一个属性绑定到一个输入文本框。
我期望的行为是:如果我改变下拉框的值,文本框应该清空,反之亦然。然而,由于我编写的监视器的方式,第一次按键(在与选择元素交互后)会吞噬掉按键操作。
肯定有一种Angular的方式可以告诉Angular不要处理这些变量的变化,但仍然允许它们的变化传播到视图中...?
$scope.$watchCollection('[selCountry, searchText]', function(newValues, oldValues, scope){ console.log(newValues, oldValues, scope.selCountry, scope.searchText); var newVal; if(newValues[0] !== oldValues[0]) { console.log('1'); newVal = newValues[0]; scope.searchText = ''; } else if(newValues[1] !== oldValues[1]) { console.log('2'); newVal = newValues[1]; scope.selCountry = ''; } $scope.search = newVal; var count = 0; if(records) records.forEach(function(o){ if(o.Country.toLowerCase().indexOf(newVal.toLowerCase())) count++; }); $scope.matches = count; });
问题出现的原因是在ng-change事件中,当选择了一个国家或者输入了搜索文本时,会调用searched()函数。在searched()函数中,首先将$scope.countries数组重置为$scope.allCountries数组,然后根据搜索文本进行过滤,最后将过滤后的结果赋值给$scope.countries数组。这样做的结果是,每次选择一个国家或者输入搜索文本时,$scope.countries数组都会被不断地修改和赋值,从而导致watchers频繁触发,性能下降。
解决方法是利用lodash库来简化数组/对象的操作,并优化代码逻辑。具体的解决方法如下:
1. 在HTML模板中引入lodash库:
2. 在JavaScript代码中使用lodash库的函数来简化操作:
angular.module('myapp',[]) .controller('MainCtrl', function($scope, $http) { $http.get('http://www.w3schools.com/angular/customers.php').then(function(response){ $scope.allCountries = _.uniq(_.pluck(_.sortBy(response.data.records, 'Country'), 'Country')); $scope.countries = $scope.allCountries; }); $scope.searched = _.debounce(function() { $scope.countries = $scope.allCountries; if ($scope.search) { var result = _.filter($scope.countries, function(country) { return country.toLowerCase().indexOf($scope.search.toLowerCase()) != -1; }); $scope.countries = result; } }, 300); });
通过使用_.debounce函数,可以将searched()函数的执行延迟300毫秒,从而减少watchers触发的次数。此外,使用lodash库的函数可以简化对数组的操作,提高代码的可读性和性能。
通过以上的修改,可以解决watchcollection swallowing an attribute being watched的问题,并提升应用的性能。
问题原因:问题出现的原因是在watchCollection事件处理程序中捕捉到了被观察属性的变化,但当改变第二个变量的值时,它也被watchCollection处理程序捕捉到并清除该值。这是因为当在作用域对象上改变selCountry的值时,watchCollection也被调用,然后它说“好的,我现在需要清除searchText”。
解决方法:可以通过使用ng-change指令来捕捉变化,并使用onChange事件处理程序来修复这个问题。尝试以下方法:
// 注释或删除当前的watchCollection事件处理程序 // 在JS文件中添加以下内容 $scope.searchTextChange = function(){ $scope.selCountry = ''; $scope.search = $scope.searchText; search($scope.search); }; $scope.selectCountryChange = function(){ $scope.searchText = ''; $scope.search = $scope.selCountry; search($scope.search); }; function search(value){ var count = 0; if(records) records.forEach(function(o){ if(o.Country.toLowerCase().indexOf(value.toLowerCase())) count++; }); $scope.matches = count; }
在HTML文件中添加以下内容:
新的plunker链接: [http://plnkr.co/edit/xCWxSM3RxsfZiQBY76L6?p=preview](http://plnkr.co/edit/xCWxSM3RxsfZiQBY76L6?p=preview)