I'm having a dropdown list with multiselect option. I want to filter out data from a complex JSON based on that array.
Selected options forms a array of data like:
$scope.myval=["Adyar","Paris","central"];
My JSON :
$scope.myTest={
"buslist":
{
"code":"1",
"message":"Success",
"fromStationCode":"71",
"searchResult":[ {
"arrivalTime":"17:00:00",
"availableSeats":"42",
"boardingPointDetails":[{
"code":"1631",
"name":"Koyambedu",
"time":"09:30:00"
},
{
"code":"961296",
"name":"Paris",
"time":"09:45:00"
}
]
]
},
{
"arrivalTime":"18:00:00",
"availableSeats":"32",
"boardingPointDetails":[{
"code":"2084",
"name":"Adyar",
"time":"09:30:00"
},
{
"code":"961296",
"name":"Madurai",
"time":"09:45:00"
}
]
]
}
}
...
};
My HTML templating is:
<tbody ng-repeat=" i in myTest.buslist.searchResult" >
<tr>
<td>{{i.arrivalTime}}</td>
<td>{{i.availableSeats}}</td>
<td>
<p ng-repeat="m in i.boardingPointDetails">{{m.name}}</p>
</td>
</tr>
</tbody>
I want to filter my data based on selected values. I had tried something like this :
$scope.matched = $scope.myTest.buslist.searchResult.boardingPointDetails.name.indexOf(data);
i.e:selected options must match "name" field in "boardingPointDetails" but it fails. Thanks in advance.
Since $scope.myTest.buslist.searchResult.boardingPointDetails is an array
$scope.myTest.buslist.searchResult.boardingPointDetails.name is not valid.
You need to use an Array function to get the correct result:
$scope.matched = $scope.myTest.buslist.searchResult.boardingPointDetails.filter(function(el) {
return el.name === data;
}).length > 0;
EDIT:
Due to your comments I understand you want to get the boardPointDetails that has the same name property as one of the data options. Where data is an Array of strings.
This will do the job:
$scope.matched = $scope.myTest.buslist.searchResult.boardingPointDetails.filter(function(el) {
return data.indexOf(el.name) === 1;
});
Related
I have created a table using ng-table as below.
$scope.tableParams = new NgTableParams({}, {
filterOptions: { filterComparator:angular.equals },
dataset:$scope.usersList
});
This my html.
<table ng-table="tableParams" show-filter="true" class="table table-condensed table-bordered">
<tr ng-repeat="user in $data">
<td data-title="'User ID'" header-class="'text-left'" sortable="'id'" filter="{ 'id': 'text' }">
{{user.id}}
</td>
<td data-title="'Username'" header-class="'text-left'" sortable="'username'" filter="{ 'username': 'text' }">
{{user.username}}
</td>
<td data-title="'Name'" filter="{status: 'select'}" filter-data="status" sortable="'status'">{{ user.status }}</td>
</tr>
</table>
When filter "status", I want to get the output as exact match. But when filter "username" I want it to be as contains. Since I have given "filterComparator" as "angular.equals " ,now the whole table is filtered as exact match. But how can I filter only "status" column as exact match and others as contains?
I don't think it can be done in a clean way.
For the same use case, I wrote a single filterComparator function, and decided the kind of comparison I wanted to do on the basis of the type of the parameters passed to the function.
function filterComparator(actual, expected) {
if (expected instanceof Date) {
// using moment.js for date comparison
return moment(actual).isSame(moment(expected), 'day');
} else {
// default: case insensitive substring match
return actual.toString().search(new RegExp(expected.toString(), 'i')) != -1;
}
}
Have you been able to solve the problem in a different way? I would be interested to hear.
I wrote a filter function to compare equality of two strings
angular.module('myApp').filter('equalComparator', function($filter) {
return function(values, searchTerm , property) {
var filtered = [];
if(typeof values != 'undefined' && typeof searchTerm != 'undefined') {
angular.forEach(values, function(value) {
if(value[property] == searchTerm ) {
filtered.push(value);
}
});
}
return filtered;
}
})
And then used this "equalComparator" in ngtable filter method as below
if(params.filter()[//column name to filter]) {
$scope.filteredData = $filter('equalComparator')($scope.filteredData,params.filter()[//column name to filter] ,//field name to filter);
}
I'm still stuck with a OrderBy issue. Data comes from $http, and looks like this:
[
{
"number":1,
"timetable": [
{
"name":"Station1",
"time":"2016-05-18T18:14:00.000Z"
},
{
"name":"Station2",
"time":"2016-05-18T18:18:00.000Z"
}
]
},
{
"number":2,
"timetable": [
{
"name":"Station1",
"time":"2016-05-18T18:24:00.000Z"
},
{
"name":"Station2",
"time":"2016-05-18T18:28:00.000Z"
}
]
}
]
So what I need is to view rows where name is for example Station2, and I need them in order by time. The rows aren't ordered by time, nor by number. Amount of timetable rows varies, so row numbers don't help either. Is it possible to order them inside ng-repeat, in style of "OrderBy time where name='Station2' "?
EDIT:
At the moment I'm showing the results without any ordering, only with filtering. Current PHP:
<tr ng-repeat="x in rows | limitTo:5">
<td>
<a href="aikataulu.php?n={{x.number}}">
<span class="label label-primary line-{{x.lineID}}">{{x.lineID}}</span> {{x.number}}
</a>
</td>
<td>
<span ng-repeat="y in x.timetable | limitTo:-1">{{y.name}}</span> //This is for showing the destination
</td>
<td>
<span ng-repeat="y in x.timetable | filter:{'name':'<?php echo $as;?>'}: true | limitTo:1">{{y.time | date:'HH:mm'}}</span>
</td>
</tr>
$as is the station to be shown. So, now the order of the list comes straight from the JSON order, so it varies a lot.
You can use the comparator as an additional argument for the filter.
So you would expand your code to:
<span ng-repeat="y in x.timetable | filter:{'name':'<?php echo $as;?>'}: true : myComparator | limitTo:1">{{y.time | date:'HH:mm'}}</span>
You need a regexp to see if the compared string values are dates and you can do something similar to:
$scope.myComparator= function (a, b) {
// regex to see if the compared values are dates
var isDate = /(-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-)/g;
// sorting dates
if (isDate.test(a.value)) {
var aDate = new Date(a.value), bDate = new Date(b.value);
return aDate.getTime() < bDate.getTime() ? -1 : 1
}
// default sorting
return a.index < b.index ? -1 : 1
}
A thing worth noting is you would need a different regular expression to find your date format. Something along the lines of the following might be sufficient:
/(\d{4})-(\d{2})-/g
NOTE: This is untested code and serves only as a guide to the right approach. Make sure your version of AngularJS supports the comparator as a filter argument.
You can order an array of objects by one of their properties with a filter function like this one:
angular.module('yourApp').filter('orderObjectBy', function() {
return function(items, field, reverse) {
var filtered = [];
angular.forEach(items, function(item) {
filtered.push(item);
});
filtered.sort(function (a, b) {
return (a[field] > b[field] ? 1 : -1);
});
if(reverse) filtered.reverse();
return filtered;
};
}
);
Use it like this
<div ng-repeat="elem in data | orderObjectBy:'number'">
// ...
</div>
I have meet a problem, I try to filter the query result, I want to filter the item.type. The filter value is bounded on the input field.
I try the following code, but it doesn't work. How can I make it correct? Thanks.
Search: <input ng-model="query">
Current filter: {{query}}
<table>
<tr ng-repeat="item in items | filter : {type : 'query'}">
<td>{{item.type}}</td>
<td>{{item.host}}</td>
</tr>
</table>
Use a custom filter
$scope.filterByType = function(item) {
return item.type == "query";
}
And the use:
<tr ng-repeat="item in items | filter : filterByType">
Just remove the quotes:
filter : {type : query}
Demo
I try the following code, it will return all when no input in the query filter.
$scope.filterByType = function(item) {
if ($scope.query == undefined || $scope.query.length == 0) {
return item;
}
return item.type.toLowerCase().indexOf($scope.query.toString().toLowerCase()) >=0 ;
};
I have objects like this:
students = {name: 'Aa_Student', class: 'A_Class'},
{name: 'Ab_Student', class: 'A_Class'},
{name: 'Ac_Student', class: 'B_Class'},
{name: 'Ba_Student', class: 'B_Class'},
{name: 'Bb_Student', class: 'C_Class'},
{name: 'Bc_Student', class: 'C_Class'}
Let's say the students object is shuffled. I use ng-repeat to show the data. I want to sort the objects in the custom order.
For example, I want to show the data like this:
Name Class
-----------------------------
Ac_Student B_Class
Ba_Student B_Class
Aa_Student A_Class
Ab_Student A_Class
Bb_Student C_Class
Bc_Student C_Class
So basically, I want to order by student's class, but it B_Class comes first, then A_Class, then C_Class. Also, I want to order by students name in alphabetic order. How can I do this?
HTML:
<table>
<tr ng-repeat="student in students | orderBy:customOrder">
...
</tr>
</table>
Controller:
$scope.customOrder = function(student) {
$scope.students = $filter('orderBy')(student, function() {
});
};
Hi you can create custom sort filter please see here http://jsbin.com/lizesuli/1/edit
html:
<p ng-repeat="s in students |customSorter:'class'">{{s.name}} - {{s.class}} </p>
</div>
angularjs filter:
app.filter('customSorter', function() {
function CustomOrder(item) {
switch(item) {
case 'A_Class':
return 2;
case 'B_Class':
return 1;
case 'C_Class':
return 3;
}
}
return function(items, field) {
var filtered = [];
angular.forEach(items, function(item) {
filtered.push(item);
});
filtered.sort(function (a, b) {
return (CustomOrder(a.class) > CustomOrder(b.class) ? 1 : -1);
});
return filtered;
};
});
Know this is old but may come in handy for others...
You could also create a simple custom sort function. "Not quite a filter":
$scope.customOrder = function (item) {
switch (item) {
case 'A_Class':
return 2;
case 'B_Class':
return 1;
case 'C_Class':
return 3;
}
};
And then use like you wanted to:
<table>
<tr ng-repeat="student in students | orderBy:customOrder">
...
</tr>
to set the orderBy as a property of the objects just quote that property name within the markup:
ng-repeat="student in students |orderBy:'name' | orderBy:'class'"
DEMO
I'm trying to create a dynamic table that could hold search results with different amount of columns.
I created a table that should have a row for every entry and a column for every datafield both populated with ng-repeat -functions, but for some reason it doesn't show any information in the columns at all, although it does create correct amount of them.
If I try to show e in {{}} it shows the correct key that exists. If I try with i in {{}} it shows the following in each column (the information is same for all columns, but different for every row):
{"etunimi":"firstname","sukunimi":"lastname","optunnus":"010101010101011001"}
Here is the html:
<table id="raporttiTulos" class="resultTable">
<tr ng-repeat="i in raportointiLista">
<td ng-repeat=" e in raportointiAvaimet">{{i.e}}</td>
</tr>
</table>
Here is the function responsible for the incoming data:
$scope.haeMaksut = function(){
$scope.raportointiAvaimet = {};
$http.post('/maksuhaku')
.then(function(res){
x = 0;
$scope.raportointiLista = res.data.message;
for(i in $scope.raportointiLista[0]){
$scope.raportointiAvaimet[x] = i;
x+=1
}
console.log($scope.raportointiAvaimet);
$scope.maksamattomat = $scope.raportointiLista.length;
$scope.lataus = true;
}, function(error){
console.log(error);
});
}
This is how the key list looks like:
Object [ "etunimi", "sukunimi", "optunnus" ]
Here are some rows from the data list:
[…]
[0…99]
0: Object { etunimi: "firstname", sukunimi: "lastname", optunnus: "101010101010101010", … }
instead of doing that you can directly access object keys.
HTML
<tr ng-repeat="i in raportointiLista">
<td ng-repeat="key in raportointiAvaimet">{{i[key]}}</td>
</tr>
Controller
$scope.haeMaksut = function () {
$scope.raportointiAvaimet = {};
$http.post('/maksuhaku')
.then(function (res) {
$scope.raportointiLista = res.data.message;
$scope.raportointiAvaimet = Object.keys($scope.raportointiLista[0]);
}, function (error) {
console.log(error);
});
}