Add fiter dynamically to ng-repeat - angularjs

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.

Related

AngularJS Show List Items based on ng-model

I'm trying to create some functionality where the user would have an input box and all the data (li's) below are hidden.
Then when a user types into the input box, those li's that match that text are show.
What would the best way to do this using angular? I've set up plunker below:
http://plnkr.co/edit/T6JOBJE4LrAtshbmaoPk?p=preview
I was thinking of setting the li's to:
li {
display: none;
}
and then was going to try an ng-if with the ng-model as the value. Something like this:
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">Search</span>
<input type="text" class="form-control" ng-model="search">
</div>
<ul>
<li ng-repeat="x in data | filter:search " ng-if="!search">{{x.name}}</li>
</ul>
Can someone help point me in the right direction? Even if its just explaining the logic.
You can just set ng-show attribute to your <ul> tag, where you will watch on length of search variable and if it's greater that zero, your list with filtered results will be shown. So, you don't need any css.
<ul ng-show="search.length">
<li ng-repeat="x in data | filter:search ">{{x.name}}</li>
</ul>
Demo on plunker.
Part of your problem is the filter matches on the empty search string. You could create a custom filter to handle this, something like this http://plnkr.co/edit/i4lsuVUmOLO3pbISu7FR?p=preview
$scope.filterName = function(datum) {
console.log($scope.search, datum);
return $scope.search !== '' && datum.name.indexOf($scope.search) !== -1;
};
Used in the template like:
<ul>
<li ng-repeat="x in data | filter:filterName">{{x.name}}</li>
</ul>
Then you would have greater control over the filter if you want to tweak it in future.

Ng-repeat orderBy date

I am trying to order the following by date:
<div class="inbox" ng-repeat="recipient in messages | orderBy: 'recipient':true">
<ul>
<div>
<li class="inboxItem">
<a ng-href="#/messaging/userChat/{{recipient.$id}}"><span> {{recipient.$id}} <br> </span></a>
<div ng-repeat="content in recipient track by $index">
<span ng-show="$last"> {{content.sender}} {{content.message}} <br> {{content.date}} <br></span>
</div>
</li>
</div>
</ul>
My data structure looks like that:
--ID: (recipient in ng-repeat)
-----Date (content in ng-repeat)
--------------Sender
--------------Message
--------------Date
-----Date (content in ng-repeat)
--------------Sender
--------------Message
--------------Date
Etc.
How do I order the list by the Date value? Why isn't my code working?
Thanks a lot!
EDIT:
Date is in form of Date() form AngularJS.
I will be able to add better description of data later, for now I can provide a screenshot of Firebase set up.
Where 1375194092807517 is the USER ID of current user, 1384934715162092 is the USER ID of the one with whom the messages are sent.
Actually I figured it out myself. Since eveytime I send new message, I set LastUpdate to the Date() value, I user the following orderBy:
<div class="inbox" ng-repeat="recipient in messages | orderBy: 'LastUpdate':true">
This way I didn't needed to use orderBy nested ng-repeat :)
Thanks to every one who wanted to help!
Use the build-in filter orderBy, as you did in the parent ng-repeat. The expression you provide could be a function in your scope

Angular - how to make filter by case sensitive

In my app, I am using the search box to filter the persons. the persons name are static(at present), how can i make this filter case sensitive?
because people can enter their name by their wish here. so I am looking this to filter by how the way they entered their name.
here is my config, but not working;
<div class="container">
<h1>Directive Test 1</h1>
<input type="search" name="search" ng-model="search" placeholder="Search a person" id="">
<div class="list" ng-controller="List">
<ul>
<li ng-repeat="person in people | filter:search:upperCase"> // not working! {{person.name}}</li>
</ul>
</div>
</div>
Any one help me please?
UPDATE
my js code :
var List = function($scope){
$scope.people = [
{name:'Mo',age:20},
{name:'Si', age:22},
{name:'Yo', age:33}
]
}
Demo is here(buggy)
You could supply a comparator function to the filter like this:
<li ng-repeat="person in people | filter:search:comparatorFunction">
and in a controller:
$scope.comparatorFunction = function (name, search) {
return (''+name).indexOf(''+search) > -1;
};
Hope this helps.
uppercase and filter are two different fitlers
change this
person in people | filter:search:upperCase
to this
person in people | filter:search | uppercase
uppercase filter is used when you want to render output html in uppercase
Now, to filter case-sensitive, use custom case sensitive filter
Updated fiddle: http://jsfiddle.net/Tw7kW/

Trigger click on first element in list in angularjs

I'm an angularjs newbie building my first app. I have a list of users that I can filter and sort:
<button ng-click="order='lastname'; reverse=!reverse">Sort by name</button>
<button ng-click="order='id'; reverse=!reverse">Sort by id</button>
<input type="text" ng-model="filter.user">
<ul class="userlist" ng-class="{blur: currentUser}">
<li ng-repeat="user in users | orderBy:order:reverse | filter:filter.user">
{{user.id}} / {{user.firstname}} {{user.lastname}}
Show details
<div ng-click="showDetails(user)">Show details in overlay</div>
</li>
</ul>
<div ng-show="details">
<div ng-click="details=!details">close</div>
{{user.custom}}
</div>
<div ng-show="currentUser" id="overlay">
{{currentUser.firstname}} {{currentUser.lastname}} {{currentUser.custom}}
<div ng-click="closeOverlay()">close</div>
</div>
I can click on a user to get his details. Now I want to realize the following scenario: When I press the enter key in the filter text input I want to show the details of the first <li /> in the list at the current time. So in jQuery I would bind a keypress event to the input which would check for the key code (13) and then would trigger: $('li').eq(0).click() which would call showDetails() on that particular user - easy.
How can I build such functionality with angular? I tried using the ng-keypress directive which lets me bind a function to a certain keypress but now I'm stuck because I don't know how to trigger the showDetails() function on the first element. Any help greatly appreciated!
This is a workaround you can give a try for the time being: make your ng- keypress handler create a list of your filtered results (that is, reapply your filters on a copy of your user list in your controller) and then call the showDetails for the first egg element of that list.
Is it ugly? Yes. It's it a bad decision if you are working with big lists? Certainly. But it will get you going till you find another way / better stackoverflow answer.
The following should work. Inside your ng-keypress handler set a property that enter was pressed, e.g. enterPressed. Then use ng-init as follows:
<li ng-init="isFirst($first, user)" ng-repeat="user in users | orderBy:order:reverse | filter:filter.user">
{{user.id}} / {{user.firstname}} {{user.lastname}}
Show details
<div ng-click="showDetails(user)">Show details in overlay</div>
</li>
And then in your controller have something like:
$scope.isFirst = function(first, user) {
if (first && enterPressed) {
enterPressed = false;
$scope.showDetails(user);
}
}
I figured out a pretty elegant solution:
In the ng-repeat you can assign an additional variable (I called it filteredUser to the current result set:
<li ng-repeat="user in (filteredUser = (users | orderBy:order:reverse |
filter:filter.user))" ng-click="showDetails(user)">
This way it is super easy to access the first item in that result set (filteredUser[0]) and pass it to a function:
<input type="text" ng-model="filter.user" ng-keypress="$event.keyCode == 13 ?
showDetails(filteredUser[0]) : null">

AngularJS - hide parent element if children loop is empty (filtered)

I have a case in which I have nested loops in which the child one is constructed by a filter function that takes parent as the argument. I also have another filter that just does a text comparison. Here is the example
<div ng-repeat="group in groups">
{{group.name}}
<div ng-repeat="material in materials | filter:filterByGroup(group) | filter:search ">
{{material.name}}
</div>
</div>
Now, my problem is that when filter:search is applied and it filters out all the results in specific group, I would like to hide the group (and not leave the empty group.name hanging without child elements).
I don't have the materials in the group it self, so I don't have that information in the parent ng-repeat scope. The question is if there is a way I can access the nested ng-repeat and see its count from the parent and hide the parent if that count is 0.
UPDATE
Here is a fiddle that better explains the situation: fiddle
The main problem is that I don't want to associate my materials with groups. I could do that if nothing else works, but it sounds like an overload (since I would then need to basically filter the results twice) if I could do it by just checking the nested loop.
Thanks
A much cleaner solution was suggested HERE.
What you need to do is wrap the relevant area with an ng-show / ng-if based on an expression that applies the filter on the data structure and extracts length. Here is how it works in your example:
<div ng-show="(materials | filter:filterByGroup(group)).length">
<div ng-repeat="group in groups">
{{group.name}}
<div ng-repeat="material in materials | filter:filterByGroup(group) | filter:search ">
{{material.name}}
</div>
</div>
</div>
This allows you to hide complex structures once they are empty due to filtering, e.g. a table of results.
I've seen this use-case a few times, here's my solution:
<div ng-repeat="group in groups">
<div ng-repeat="material in materials | filter:filterByGroup(group) | filter:search ">
<span ng-show="$first">
{{group.name}}<br/>
</span>
{{material.name}}
</div>
</div>
You can use $first or $last within the scope of the ng-repeat to show only for the first and last of each group. if there is no $first, it won't show the group name.
I just implemented this on my blog and updated your fiddle here: http://jsfiddle.net/ke793/1/
I'm not sure if this is the most elegant solution, but it seems fairly simple and it works. I'd love to see how others solved this.
Update: just realized you can use ng-if to prevent the group name from hitting the dom at all outside of the $first element. Little bit cleaner than ng-hide/ng-show, which sets display: none to the extra header every time.
If you can ask for the materials by group and you expect to do that for each group anyway, why not do that right away when you initialize the view and build a model with groups that have materials? If you can do that you can use ng-show to only hide groups that have materials.
You seem to need to know that a group has materials or not somehow? Here's a fiddle without knowing much of the background story:
<div ng-controller="MyCtrl">
<div ng-repeat="group in groups">
<div ng-show="groupHasMaterials(group)">{{group.name}}</div>
<div ng-repeat="material in materialsByGroup(group)">
<div>{{material.name}}</div>
</div>
</div>
</div>
<script>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
var groups = [
{'name':'group one'},
{'name':'group two'}
];
var materials = [
{'name':'material1'},
{'name':'material2'},
{'name':'material3'}
];
$scope.groups = groups;
$scope.materials = materials;
$scope.groupHasMaterials = function(group){
return $scope.materialsByGroup(group).length > 0;
}
$scope.materialsByGroup = function(group){
return group.name === 'group one'
? [materials[0], materials[1]]
: [];
}
}
</script>
fiddle with groups

Resources