angular ng-repeat if property is defined - angularjs

I'm trying to ng-repeat through an array, but need to hide if a property is undefined.
I tried doing to do is this:
<div ng-repeat="person in people | filter:search" ng-if="last == undefined">
{{person.last}}, {{person.first}}
</div>
Heres a basic jsfiddle of what I'm trying to do:
http://jsfiddle.net/HB7LU/4556/
Thank you!

<div ng-controller="MyCtrl">
<div ng-repeat="person in people | filter:search" ng-show="person.last">
{{person.last}}, {{person.first}}
</div>
Try testing for person.last instead of just 'last'.
I used ng-show instead of ng-if as well.

If you want to just hide the rows, then mccainz's answer will work. If you want to actually remove them from the DOM, then create a filter:
$scope.fullNameFilter = function(person){
return person.last;
};
HTML
<div ng-repeat="person in people | filter: fullNameFilter">
JSFIddle

Related

Using ng-repeat in filter

I think popular question, but I don't found solution. Look e.g. I have object {title:..., book:.... author:...} and would like filter my view by title like below:
<div ng-repeat="product in main.products | filter: {{product.title}}">
<span>{{product.author}}</span>
</div>
In <span> author has shown, but filter not working.
If you get your filter value from server side, you can easily simulate it as:
$scope.by_title = '';
$timeout(function(){
$scope.by_title = 'on';
},3000);
and:
<tr ng-repeat="obj in objs | filter:{ title: by_title }">
DEMO PLUNKR
As you commented, you should use orderBy filter for this.
<div ng-repeat="product in main.products | orderBy: 'title'">

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.

Variable in directive

This does not seem possible, but is it:
<div ng-repeat="item in myitems | {{ searchfilter }}">
<span>{{ item.title }}</span>
</div>
or some variant of it? All I get are no results.
searchfilter should not have {{ }} around it. Since this is a directive, angular knows how to deal with the variable. You only need the braces when trying to inject a variable from angular scope into the non-angular HTML.
You should correct syntax to this instead:
<div ng-repeat="item in myitems | filter:searchfilter">
With Search filter Moustaches :<span>{{ item.title }}</span>
</div>
Have created a small plunk for reference.
http://plnkr.co/edit/tpl:rfqcl9AHEoJZEEJxyNn2?p=preview

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

Different class for the last element in ng-repeat

I am creating a list using ng-repeat something like this
<div ng-repeat="file in files">
{{file.name}}
</div>
But for the last element alone I would like to have a class (<div class="last">test</div>) included to it. how can i achieve this using ng-repeat?
You can use $last variable within ng-repeat directive. Take a look at doc.
You can do it like this:
<div ng-repeat="file in files" ng-class="computeCssClass($last)">
{{file.name}}
</div>
Where computeCssClass is function of controller which takes sole argument and returns 'last' or null.
Or
<div ng-repeat="file in files" ng-class="{'last':$last}">
{{file.name}}
</div>
It's easier and cleaner to do it with CSS.
HTML:
<div ng-repeat="file in files" class="file">
{{ file.name }}
</div>
CSS:
.file:last-of-type {
color: #800;
}
The :last-of-type selector is currently supported by 98% of browsers
To elaborate on Paul's answer, this is the controller logic that coincides with the template code.
// HTML
<div class="row" ng-repeat="thing in things">
<div class="well" ng-class="isLast($last)">
<p>Data-driven {{thing.name}}</p>
</div>
</div>
// CSS
.last { /* Desired Styles */}
// Controller
$scope.isLast = function(check) {
var cssClass = check ? 'last' : null;
return cssClass;
};
Its also worth noting that you really should avoid this solution if possible. By nature CSS can handle this, making a JS-based solution is unnecessary and non-performant. Unfortunately if you need to support IE8> this solution won't work for you (see MDN support docs).
CSS-Only Solution
// Using the above example syntax
.row:last-of-type { /* Desired Style */ }
<div ng-repeat="file in files" ng-class="!$last ? 'class-for-last' : 'other'">
{{file.name}}
</div>
That works for me! Good luck!
You could use limitTo filter with -1 for find the last element
Example :
<div ng-repeat="friend in friends | limitTo: -1">
{{friend.name}}
</div>
The answer given by Fabian Perez worked for me, with a little change
Edited html is here:
<div ng-repeat="file in files" ng-class="!$last ? 'other' : 'class-for-last'">
{{file.name}}
</div>

Resources