watchcollection swallowing an attribute being watched

柔情痞子 提交于 2019-12-13 08:34:39

问题


There are two attributes selCountry and searchText. There is a watch that monitors these two variables. The 1st one is bound to a select element, other is a input text field.

The behavior I expect is: If I change the dropdown value, textbox should clear out, and vice versa. However, due to the way I have written the watch, the first ever key press (post interacting with select element) swallows the keypress.

There must be some angular way of telling angular not to process the variable changes happening to those variables; yet still allow their changes to propagate to the view...?

  $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;
  });

Plunk


回答1:


I think the problem you are encountering is that you capture a watch event correctly, but when you change the value of the second variable, it is also captured by the watchCollection handler and clears out that value as well. For instance:

selCountry = 'Mexico'

You then change

selText = 'City'

The code captures the selText change as you'd expect. It continues to clear out selCountry. But since you change the value of selCountry on the scope object, doing that also invokes watchCollection which then says "okay I need to now clear out searchText".

You should be able to fix this by capturing changes using onChange event handlers using ng-change directive. Try the following

// 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;
  }

And in your HTML file

<!-- 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()"/>

New plunker: http://plnkr.co/edit/xCWxSM3RxsfZiQBY76L6?p=preview




回答2:


I think you are pushing it too hard, so to speak. You'd do just fine with less complexity and watches.

I'd suggest you utilize some 3rd party library such as lodash the make array/object manipulation easier. Try this plunker http://plnkr.co/edit/YcYh8M, I think it does what you are looking for.

It'll clear the search text every time country item is selected but also filters the options automatically to match the search text when something is typed in.

HTML template

<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;
      }
    };
  });


来源:https://stackoverflow.com/questions/29753111/watchcollection-swallowing-an-attribute-being-watched

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!