Reputation: 3415
I am Building a state autocomplete with AngularJS
The html doesn't seem to be responding to the $scope.$watch, even though I can see through console.logs that this.filteredStates is getting assigned to states initially and then changing when typing stuff in the input. What's missing?
angular.module('stateAutocomplete', [])
.controller('stateAutocompleteCtrl', function($scope) {
var states = ["Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District Of Columbia", "Federated States Of Micronesia", "Florida", "Georgia", "Guam", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Marshall Islands", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Northern Mariana Islands", "Ohio", "Oklahoma", "Oregon", "Palau", "Pennsylvania", "Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virgin Islands", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"];
this.filteredStates = [];
$scope.$watch(angular.bind(this, function() {
return this.input;
}), function(newVal, oldVal) {
if (newVal === oldVal) {
this.filteredStates = states;
} else {
this.filteredStates = states.filter(function(state) {
state = state.toLowerCase();
var lowerCaseInput = newVal.toLowerCase();
return state.indexOf(lowerCaseInput) > -1;
})
}
})
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
</head>
<body ng-app="stateAutocomplete">
<div ng-controller="stateAutocompleteCtrl as state" class="container">
<input ng-model="state.input" class="autocomplete"></input>
<ul ng-repeat="state in state.filteredStates">
<li>{{state}}</li>
</ul>
</div>
<script src="app.js"></script>
</body>
Upvotes: 1
Views: 75
Reputation: 1120
The issue is that you forget to bind the second function in your $watch. The code below works; (but is ugly)
angular.module('stateAutocomplete', [])
.controller('stateAutocompleteCtrl', function($scope) {
var states = ["Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District Of Columbia", "Federated States Of Micronesia", "Florida", "Georgia", "Guam", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Marshall Islands", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Northern Mariana Islands", "Ohio", "Oklahoma", "Oregon", "Palau", "Pennsylvania", "Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virgin Islands", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"];
this.filteredStates = [];
$scope.$watch(
angular.bind(this, function () {
return this.input;
}),
angular.bind(this, function(newVal, oldVal) {
if (newVal === oldVal) {
this.filteredStates = states;
} else {
this.filteredStates = states.filter(function(state) {
state = state.toLowerCase();
var lowerCaseInput = newVal.toLowerCase();
return state.indexOf(lowerCaseInput) > -1;
});
}
})
);
});
A better way to bind variables to the controller is to introduce a "vm" variable inside the closure, like this: (For a better explanation on the "why", see for example: http://www.johnpapa.net/angularjss-controller-as-and-the-vm-variable/)
angular.module('stateAutocomplete', [])
.controller('stateAutocompleteCtrl', function($scope) {
var vm = this;
var states = ["Alabama", "Alaska", "American Samoa", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware", "District Of Columbia", "Federated States Of Micronesia", "Florida", "Georgia", "Guam", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana", "Maine", "Marshall Islands", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi", "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", "New York", "North Carolina", "North Dakota", "Northern Mariana Islands", "Ohio", "Oklahoma", "Oregon", "Palau", "Pennsylvania", "Puerto Rico", "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virgin Islands", "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"];
vm.filteredStates = [];
$scope.$watch(
function () {
return vm.input;
},
function (newVal, oldVal) {
if (newVal === oldVal) {
vm.filteredStates = states;
} else {
vm.filteredStates = states.filter(function (state) {
state = state.toLowerCase();
var lowerCaseInput = newVal.toLowerCase();
return state.indexOf(lowerCaseInput) > -1;
});
}
}
);
});
Upvotes: 4