AngularJS Show List Items based on ng-model - angularjs

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.

Related

How to use ng-switch in angularjs

I was trying to display some content using ng-switch:
<div ng-app ng-controller="ctrl" >
<div ng-repeat="list in statusList">
<p ng-switch on="list">
<span ng-switch-when="incorrect">
i am incorrect
</span>
<span ng-switch-when="stuff">
i am stuff
</span>
<span ng-switch-when="wrong">
i am wrong
</span>
<span ng-switch-default>
Correct
</span>
</p>
</div>
</div>
controller
function ctrl($scope){
$scope.statusList=["incorrect","wrong","stuff"];
}
Getting the output like this:
i am incorrect
i am wrong
i am stuff
But I need output to display in order what I specified. i.e.
i am incorrect
i am stuff
i am wrong
How can I do this, and one important point is we should not change the order in controller.
You can create custom order by function, something like this.
<div ng-repeat="list in statusList | orderBy:myValueFunction">
You can order it alphabetically (with filter), but I would not recommend it because you will probably add new element that are not ordered alphabetically.
ng-repeat iteration uses the order of your list. You can either define a custom filter to order the list as you want or use another approach:
Define a 'contains' filter, returning true if an array contains an element:
.filter('contains', [function() {
return function(array, element) {
return array.indexOf(element) > -1;
}
}])
Use ng-ifs for your template (no repeat):
<div ng-if="statusList | contains : 'incorrect'">i am incorrect</div>
<div ng-if="statusList | contains : 'stuff'">i am stuff</div>
<div ng-if="statusList | contains : 'wrong'">i am wrong</div>
This way you can define whatever order you want to have.
Plunkr: http://plnkr.co/edit/yaYodJAVCVQ55KbOrf3A?p=preview

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/

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.

Why am I getting "Error: 'undefined' is not a function (evaluating 'items.split(',')')" here?

I'm getting the following error while typing into the field filtered by 'completeList'. Why is this happening?
JavaScript
angular.module('myApp', ['timer'])
.controller('AppCtrl',['$scope', function($scope){
$scope.gameOn = true;
$scope.leaders = true;
$scope.myScore = true;
}])
.filter('completeList', function() {
return function(items) {
var list = [];
if(items) {
list = items.split(',');
var last = list[list.length - 1];
if(items.charAt(items.length - 1) != ',' || last.length === 0)
list.pop();
}
return list;
};
});
HTML
<div ng-show="gameOn" ng-controller="LabelCtrl" class="row marketing">
<div class="col-lg-4">
<h4>Enter comma-separated labels for this image</h4>
<form role="form" class="form-inline" >
<input ng-list ng-model="labels" placeholder="Enter labels" class="form-control" type="text" >
<button class="form-control" class="btn btn-xs btn-success">Submit</button>
</form>
</div>
<div class="col-lg-2">
<h4>Labels</h4>
<div>
<ol>
<li ng-repeat="label in labels track by $index | completeList">
{{ label }}
</li>
</ol>
</div>
</div>
The good news is that you only have a minor Angular syntax error. It is actually mentioned in the documentation:
Filters should be applied to the expression, before specifying a
tracking expression.
...
For example: 'item in items | filter:searchText track by item.id' is a pattern that might be used to apply a filter to items in conjunction with a tracking expression.
Given this knowledge, just change your ngRepeat line to the following, it does work exactly as you intended and works perfectly on my side:
<li ng-repeat="label in labels | completeList track by $index">
I do not know what the data structure of labels so here is my best stab at it. Filters are applied onto the instance of your iteration of your loop. It looks like you may be trying to apply the filter to the entire collection instead of that index of the loop. The filter is applied to label not labels. In this case you cannot split it. Again I dont know your data structure so I am kind of guessing here. It would be helpful if you could reveal what labels is.
Thanks,
Jordan

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">

Resources