Reputation: 5021
I am a newbie to Angular JS and I have been trying to build a demo ASP .Net MVC Application using it. Putting it simply, I have a list of countries each having a list of 3 associated cities
var myModule = angular
.module("myModule", [])
.controller("myController", function ($scope) {
var countries = [
{
name: "UK",
cities: [
{name: "London"},
{name: "Birmingham" },
{name: "Manchestar" }
],
flag: "/Images/UK.gif",
foundationDate: new Date("May 20,1916"),
likes: 0,
dislikes: 0
},
{
name: "USA",
cities: [
{name: "Los Angeles"},
{name: "Houston"},
{name: "Florida"},
],
flag: "/Images/USA.png",
foundationDate: new Date("August 01,1887"),
likes: 0,
dislikes: 0
},
{
name: "INDIA",
cities: [
{ name: "Hyderabad" },
{ name: "Mumbai" },
{ name: "Kolkata" },
],
flag: "/Images/INDIA.jpg",
foundationDate: new Date("August 15,1947"),
likes: 0,
dislikes: 0
}
];
and in my view page, I am displaying them all.
I have a Search text box that can search across Country Names and also across the city names .For that there is the $scope.search function.
$scope.search = function (country) {
if ($scope.searchText == undefined) {
return true;
}
angular.forEach(country.cities, function (item) {
if (item.name.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1)
return true;
});
return false;
}
});
Here is the view code
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myModule">
<head>
<title></title>
<script src="Scripts/angular.js"></script>
<script src="Scripts/MyModuleScript.js"></script>
<style>
table, th, td {
border-collapse:collapse;
border:1px solid black;
}
th, td {
text-align:center;
vertical-align:middle;
}
</style>
</head>
<body ng-controller="myController">
Rows to display : <input type="number" step="1" min="0" max="3" ng-model="rowLimit" />
<br />
<br />
Search : <input type="text" placeholder="Search Countries & Cities" ng-model="searchText" />
<br />
<br />
<div>
<table style="padding:5px">
<thead>
<tr>
<th>Country</th>
<th>City 1</th>
<th>City 2</th>
<th>City 3</th>
<th>Flag</th>
<th>Foundation Date</th>
<th>Likes</th>
<th>Dislikes</th>
<th colspan="2">Actions</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="country in countries | orderBy : '+foundationDate' | limitTo: rowLimit | filter : search">
<td>{{ country.name }}</td>
<td ng-repeat="city in country.cities">
{{ city.name }}
</td>
<td><img ng-src="{{ country.flag }}" style="height:100px;width:150px"/> </td>
<td>{{ country.foundationDate | date : "dd/MM/yyyy" }}</td>
<td>{{ country.likes }}</td>
<td>{{ country.dislikes }}</td>
<td><input type="button" value="Like" ng-click="incrementLikes(country)"</td>
<td><input type="button" value="Dislike" ng-click="incrementDislikes(country)"</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
But the search function is not working properly . Here is a screenshot of the html view page
I know somehow the logic is not at all devised correctly for the search function. Could someone please help me through ?
Upvotes: 0
Views: 157
Reputation: 21
Assuming that the search function is being called you are only returning a boolean value for the filter to search the object. Since the model object you are passing to the filter does not have a boolean property to search against that would yield no results. What you want to do is to filter the string value of searchText against the filtered model.
If you only want to search explicitly for city name of the model I would suggest passing the property name to the filter.
<tr ng-repeat="country in countries | filter : {cities.name : searchText} : true | limitTo: rowLimit | orderBy : '+foundationDate'">
To search for country and city names I would suggest creating a custom filter and pass the filter the searchText model.
[ModuleNameHere].filter('filterCountryCityNames', function() {
return function(obj, searchValue) {
var options = [];
if (searchValue === undefined || searchValue === null)
return obj;
searchValue = searchValue.toLowerCase();
angular.forEach(obj, function(value) {
var foundCity = value.cities.map(function(r) {
return r.name.toLowerCase().indexOf(searchValue) >= 0;
}).sort().pop();
if (value.name.toLowerCase().indexOf(searchValue) >= 0 || foundCity) {
options.push(value);
}
});
return options;
}
})
You would use this like the built in Angular filter in the html markup.
<tr ng-repeat="country in countries | filterCountryCityNames : searchText | orderBy : '+foundationDate'| limitTo: rowLimit ">
Upvotes: 2
Reputation: 23502
I think you're problem might just be the anonymous function in your forEach
. It will return true to the anonymous function but not to the outer function $scope.search()
. So instead of returning directly from a function mutate a variable and return that at the end, or use reduce
, instead of forEach.
$scope.search = function (country) {
if ($scope.searchText == undefined) {
return true;
}
if (country.name.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1)
return true;
var found = false;
angular.forEach(country.cities, function (item) {
if (item.name.toLowerCase().indexOf($scope.searchText.toLowerCase()) != -1)
found = true;
});
return found;
}
Upvotes: 1