ng-repeat with filter for HTML table - angularjs

I am using Angular doing a minimal search function where I used filter and ng-repeat to print a table on HTML page.
I am trying to write a custom filter that helps me implement filter data by keywords input.
<div>
<label>Filter</label>
<input ng-model="filterText" type="text" placeholder="Keywords"><br>
<p><b>Filter by: </b>{{filterText}}</p>
</div>
<div>
<tr ng-repeat="x in data | myFilter: filterText">
<td>{{x.Key.Food}}</td>
<td>{{x.Key.Color}}</td>
</tr>
</div>
And I have a script code that customs myFilter
app.filter("myFilter",function(){
return function(input,filterText){
if(input["Key"]["Food"]==filterText){
return input;
}
}
})
Here is sample of JSON file that I want to apply on this code
[
{Key:{Food:"Apple",Color:"Red"},Value:{Amount:"1"}},
{Key:{Food:"Orange",Color:"Orange"},Value:{Amount:"2"}}
]
The problem I am facing is that I expect that by calling x in data x will be an object from JSON sample. And when I access it; I could access x.Key.Food etc.
However, it didn't work out because the key-pair is not defined in javascript not like Foreach in Java.

The right way to use custom filters is {{ expression | filter }}.
You can use built-in filter for this.
<tr ng-repeat="x in data | filter : { Key: { Food: filterText }} : true">
<td>{{x.Key.Food}}</td>
<td>{{x.Key.Color}}</td>
</tr>

Related

ng repeat filter on dynamically created variable

Previously I've used a trick to dynamically generate a variable like this:
<div ng-click="showHide=(showHide ? false : true)">toggle bool</div>
<header ng-show="showHide"></header>
The code above will generate a local variable called showHide that I can use on ng-* attributes. In this case, when the div is clicked, the header is hidden.
Is there a way to create a similar solution for ng-repeat's filter, without having to add functionality to the controller (like in the example above)?
In the example below I have a timeline with a bunch of items. I've also got a statistics table over what items exist in this timeline. I want to be able to filter these items by category in the same approach as i did with the showHide example.
This is a snippet of my code:
<!-- stat table -->
<tr ng-repeat="type in $ctrl.typeOfCategory">
<td ng-click="filterCategory=(filterCategory ? type.name : '')">{{type.name}}</td>
</tr>
<!-- timeline -->
<div class="timeline-item" ng-repeat="msg in $ctrl.msgs | filter: filterCategory">
<div class="category">{{msg.type}}</div>
</div>
So, whenever i click an item in the table, i want the timeline to filter all the other items out. In my mind, filterCategoryshould now contain the value of what {{type.name}} is, and filter everything else out.
Is something like this achievable in angular, or am I stretching this technique to its limits?
Thanks.
ng-repeat creates is own scope, You should define filterCategory in controller scope i.e. $ctrl.filterString and then use it..
<!-- stat table -->
<tr ng-repeat="type in $ctrl.typeOfCategory">
<td ng-click="$ctrl.filterString=((type.name == $ctrl.filterString) ? '' : type.name)">{{type.name}}</td>
</tr>
<!-- timeline -->
<div class="timeline-item" ng-repeat="msg in $ctrl.msgs | filter: {type : $ctrl.filterString}">
<div class="category">{{msg.type}}</div>
</div>

Angular js custom filter to array

I want to apply custom filter to array ,here is the code ,i am newbie to angular js.Please help me figure out.How to apply custom filter to array,is it possible to apply custom filter to array
I want to make every 2nd letter of name capital using this filter but the filter is not being applied to x.name.
<div ng-app="myapp" ng-controller="my">
<table border="1">
<tr>
<td ng-click="orderbyme('name')">Name</td>
<td ng-click="orderbyme('city')">City</td>
</tr>
<tr ng-repeat="x in names | orderBy:myorder">
<td>{{x.name | myformat}}</td>
<td>{{x.city}}</td>
</tr>
</table>
</div>
<script>
var a=angular.module('myapp',[]);
a.filter('myformat',function(){
return function(x.name){
var i,c,j,txt="";
j=x.name;
for(i=0;i<x.length;i++) {
c=j.[i];
if(i%2==0){
c = c.toUpperCase();
}
txt=txt+c;
}
return txt;
};
});
a.controller('my',function($scope){
$scope.names= [{name:'sarthak ',city:'nagpur'},
{name:'sayali ',city:'pune'},
{name:'amit ',city:'mumbai'},
{name:'komal ',city:'saoner'},
{name:'dhiraj ',city:'wardha'},
{name:'nikhil ',city:'yavatmal'},
{name:'sanjeev ',city:'delhi'},
{name:'bhavin ',city:'banglore'}
]
$scope.orderbyme=function(x){
$scope.myorder=x;
}
});
</script>
Do you want to do is order when you click on the header of the table?
It is a little more explicit about what you want to do.

Weird bug: AngularJS can search single fields but not multiple fields

I am writing an app using Angular 1.3. I want to search through a table by any word/field; one search box for everything.
Currently I am able to get my search box to search through a specific field fine by doing:
<label>Search: <input ng-model="searchKeyword.title"></label>
or
<label>Search: <input ng-model="searchKeyword.author"></label>
Those work fine. However, when I try to search all the fields at the same time by doing:
<label>Search: <input type = "text" ng-model="searchKeyword"></label>
It doesn't work at all.
This is my code on the table:
<label>Search: <input ng-model="searchKeyword"></label>
<table ng-repeat="post in posts | orderBy: sort | filter: searchKeyword">
<tr>
<td> {{post.title}} </td>
<td> {{post.author}} </td>
<td> {{post.content}} </td>
<td> {{post.date | date: "d/M/yyyy"}} </td>
</tr>
</table>
And this is inside my main controller:
$scope.posts = posts.posts;
$scope.searchKeyword = "";
Please tell me what exactly is causing this weird bug. Thank you.
Its because ng-repeat create a new scope and cannot write in to a primitive property of its parent scope.but can write in to an object of its parent scope.
A scope (prototypically) inherits properties from its parent scope.
this post explains it well.What you want here is a custom filter check the ng-modal against each property in your object.
. filter('customFilter', function() {
return function(product,query) {
var out = [];
angular.forEach(product,function(value,key){
if(value['author'].indexOf(query)>-1 || value['title'].indexOf(query)>-1)
{
out.push(value)
}
})
return out;
}
})
Here is a working example
i found this post very late. Anyway my suggestion may helpful to other viewer.
There is a solution for weird bug in weird way.
I found this post is very useful for use of multiple filters in controller with example of big data table search.
(after reading the above linked post)
But you dont need to include multiple watcher and multiple input fields in every column of table, for your scenario you will just need the below code change after static json declaration.
$scope.$watch('searchKeyword', function(val) {
$scope.items = $filter('filter')($scope.items2, val); });
considering searchKeyword is the ng-model of input field to search.

Add fiter dynamically to ng-repeat

I want add the filters to the ng-repeat depending on there checkbox state.
<li ng-repeat="user in users | filter: filters">
{{user.name}} {{user.job}} {{user.min}}-{{user.max}}
</li>
Can filters be an array?
The second Questions is, how can i show all records, when $scope.min and $scope.max are empty (at init)?
http://jsfiddle.net/nofear87/H5GMD/3/
Yes, you can change filters dynamically quite easily, just assign a scope variable and you can modify it.
Example here: http://plnkr.co/edit/Au8KFg?p=preview
If you have
<li ng-repeat="user in users | filter: filters">
then your $scope variable is
$scope.filters = {minMax: false, ... };
As for the checkboxes, if your
<input ng-model="minMaxFilter" type="checkbox" ng-change="filters['minMax] =! filters[minMax]"/>MinMAX
if you want to just change the state of a filter
or if you want to add a new filter, you can attach a function with ng-click or just push a new value
<input ng-model="newFilterToAdd" type='text' > <button ng-click="filters.push(newFilterToAdd);">Add Filter</button>
to show all records, you need to not apply the filter (such as making it empty) or assigning a null to it
You can try adding two filters for your requirement.
<li ng-repeat="user in users | filter: searchText | minMax : filterParams">
{{user.name}} {{user.job}} {{user.min}}-{{user.max}}
</li>
Here is working Fiddle.
Hope it will help you.

ng-repeat filter with filtered properties

I have a list of data that I would like to search through using Angular's typical filtering.
I have an array of objects (one of a few below):
{
vendor: 'Joan\'s Produce',
date: '2014-04-07',
total: 888.11,
note: 'insert note',
description: 'fresh produce',
terms: 'Net 10',
deliverer: 'Joe Truck',
paid: true
}
In the <thead> I have input fields to search the date and total fields.
<th style="vertical-align:text-top; width:250px;">Date<br />
<div class="input-group input-group-sm">
<input type="text" class="form-control" ng-model="dateQuery.date" />
<span class="input-group-addon"><button type="button" class="close" aria-hidden="true" ng-click="dateQuery=''">×</button></span>
</div>
</th>
The data in the table has a filter of it's own:
<tr ng-repeat="inv in invoices | filter:dateQuery | filter:amountQuery">
<td>{{inv.date | date:'MM/dd/yyyy'}}</td>...
<td>{{inv.total | currency}}</td>
</tr>
The filters within the ng-repeat format the date and change the total to a currency. When I now search those filters, it seems to only search the raw data from which the ng-repeat is pulling from.
Is there a way to build the input filters in a way that they will search the filtered result? For instance I have to search the dates with 2014-04-07, and can't add a $ in the total filter.
I have build a demo here
The filters on ng-repeat will only filter the raw data, this is how ng-repeat works. To filter on the output from the filters in your table data cells, I can see two options:
Attach prefiltered values for date and currency to the objects you are filtering. In order to keep things somewhat DRY, you can use the filters themselves for this purpose, in a controller or elsewhere fitting:
object.currencyFlat = $filter('currency')(object.total);
Build a custom filter dynamically filtering on the value you present visually in the table:
angular.module('myModule').filter('myCurrencyFilter', function($filter) {
return function(array, text) {
// Could be more sophisticated
return array.filter(function(item) {
return $filter('currency')(item).indexOf(text) !== -1;
});
}
});
Of these two, the first would be much quicker, as it only formats the object's total as a currency once.
I think neither of these approaches are particularly beautiful. I would love to see a better solution.
I ended up leveraging Underscore.js to run a foreach loop on the scope object
_.each($scope.invoices, function (invoice) {
invoice.filteredDate = $filter('date')(invoice.date, 'MM/dd/yyyy');
invoice.filteredTotal = $filter('currency')(invoice.total, '$');
});
Then referenced the new fields in my HTML
<tr ng-repeat="inv in invoices | orderBy:predicate:reverse | filter:dateQuery | filter:totalQuery">
<td>{{inv.filteredDate}}</td>
<td>{{inv.vendor}}</td>
<td>{{inv.filteredTotal}}</td>
<td>{{inv.terms}}</td>
<td class="center"><input type="checkbox" ng-model="inv.paid" disabled /></td>
<td class="center">
<a ng-click="invoice(inv, $index)"><i class="fa fa-edit"></i></a>
</td>
</tr>

Resources