watchcollection 吞下一个被监视的属性
watchcollection swallowing an attribute being watched
有两个属性selCountry
和searchText
。有一个监视这两个变量的手表。第一个绑定到 select 元素,另一个是输入文本字段。
我期望的行为是:如果我更改下拉值,文本框应该清除,反之亦然。然而,由于我编写手表的方式,第一次按键(post 与 select 元素交互)吞下了按键。
必须有某种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;
});
我认为您遇到的问题是您正确捕获了 watch 事件,但是当您更改第二个变量的值时,它也被 watchCollection 处理程序捕获并清除了该值。例如:
selCountry = 'Mexico'
你接着改
selText = 'City'
代码如您所料捕获了 selText 更改。它继续清除 selCountry。但是由于您更改了作用域对象上的 selCountry 的值,这样做也会调用 watchCollection,然后它会显示 "okay I need to now clear out searchText".
您应该能够通过使用 ng-change 指令使用 onChange 事件处理程序捕获更改来解决此问题。尝试以下
// Comment out/remove current watchCollection handler.
// Add the following in JS file
$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 文件中
<!-- Add ng-change to each element as I have below -->
<select ng-options="country for country in countries" ng-model="selCountry" ng-change="selectCountryChange()">
<option value="">--select--</option>
</select>
<input type="text" ng-model="searchText" ng-change="searchTextChange()"/>
新 plunker:http://plnkr.co/edit/xCWxSM3RxsfZiQBY76L6?p=preview
可以这么说,我觉得你太过分了。你会做的很好,复杂度较低 watches
.
我建议您使用一些第 3 方库,例如 lodash the make array/object manipulation easier. Try this plunker http://plnkr.co/edit/YcYh8M,我认为它可以满足您的需求。
它会在每次选择 country
项时清除 search text
,但也会在输入内容时自动过滤 options
以匹配搜索文本。
HTML模板
<div ng-controller="MainCtrl">
<select ng-options="country for country in countries"
ng-model="selected"
ng-change="search = null; searched();">
<option value="">--select--</option>
</select>
<input type="text"
placeholder="search here"
ng-model="search"
ng-change="selected = null; searched();">
<br>
<p>
searched: {{ search || 'null' }},
matches : {{ search ? countries.length : 'null' }}
</p>
</div>
JavaScript
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 = 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;
}
};
});
有两个属性selCountry
和searchText
。有一个监视这两个变量的手表。第一个绑定到 select 元素,另一个是输入文本字段。
我期望的行为是:如果我更改下拉值,文本框应该清除,反之亦然。然而,由于我编写手表的方式,第一次按键(post 与 select 元素交互)吞下了按键。
必须有某种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;
});
我认为您遇到的问题是您正确捕获了 watch 事件,但是当您更改第二个变量的值时,它也被 watchCollection 处理程序捕获并清除了该值。例如:
selCountry = 'Mexico'
你接着改
selText = 'City'
代码如您所料捕获了 selText 更改。它继续清除 selCountry。但是由于您更改了作用域对象上的 selCountry 的值,这样做也会调用 watchCollection,然后它会显示 "okay I need to now clear out searchText".
您应该能够通过使用 ng-change 指令使用 onChange 事件处理程序捕获更改来解决此问题。尝试以下
// Comment out/remove current watchCollection handler.
// Add the following in JS file
$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 文件中
<!-- Add ng-change to each element as I have below -->
<select ng-options="country for country in countries" ng-model="selCountry" ng-change="selectCountryChange()">
<option value="">--select--</option>
</select>
<input type="text" ng-model="searchText" ng-change="searchTextChange()"/>
新 plunker:http://plnkr.co/edit/xCWxSM3RxsfZiQBY76L6?p=preview
可以这么说,我觉得你太过分了。你会做的很好,复杂度较低 watches
.
我建议您使用一些第 3 方库,例如 lodash the make array/object manipulation easier. Try this plunker http://plnkr.co/edit/YcYh8M,我认为它可以满足您的需求。
它会在每次选择 country
项时清除 search text
,但也会在输入内容时自动过滤 options
以匹配搜索文本。
HTML模板
<div ng-controller="MainCtrl">
<select ng-options="country for country in countries"
ng-model="selected"
ng-change="search = null; searched();">
<option value="">--select--</option>
</select>
<input type="text"
placeholder="search here"
ng-model="search"
ng-change="selected = null; searched();">
<br>
<p>
searched: {{ search || 'null' }},
matches : {{ search ? countries.length : 'null' }}
</p>
</div>
JavaScript
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 = 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;
}
};
});