I created a filter that I want to pass an item property, and not the item itself. Is that possible?
The following does not work (item.param1 fails):
ng-reapeat="item in items | filter : fnFilter(item.param1)"
$scope.fnFilter = function(value) {
return value == "test";
}
Your question is quite unclear sdince you don't tell really what is your goal.
So if i just restrict to what i see there and following the link Angular filter exactly on object key already provided by #CeylanMumumKocabas you would have
ng-repeat="item in items | filter:{'param1': 'test'}"
Now let's consider you want something more complex : the only way i see would be to pass the name of the attribute to the filter :
ng-reapeat="item in items | myFilter:'param1'"
myApp.filter('myFilter', function () {
return function(inputs,attributeName) {
var output = [];
angular.forEach(inputs, function (input) {
if (input[attributeName] == 'test')
output.push(input);
});
return output;
};
});
Note that if you want to go more than one level, you'll have to use $eval or make add some code for this to work.
I have one set of JSON data consisting of the following two objects:
{
"date":"20160118",
"entity":"01",
"security":{
"securityID":"191457",
"identifiers":[
{
"value":"345342532",
"type":"fii"
},
{
"value":"32453452",
"type":"isin"
},
{
"value":"48125D886",
"type":"cusip"
}
]
}
}
And:
{
"date":"342534543",
"entity":"01",
"security":{
"securityID":"3425435",
"identifiers":[
{
"value":"32543543",
"type":"fii"
}
]
}
}
I am creating a table using only AngularJS expressions and HTML.
I'm running into trouble when accessing security.identifiers[#].value. Depending on how many identifiers a security has - they may be in different array positions - meaning an "fii" could end up in the same column as a "cusip" for the previous row. Is there a way within my angular expression I can search through an array and find a string? In this case identifiers.type will be the key to knowing which column it is placed in. I've tried looping through in my javascript and providing an index to my expression, but I seem to be running into closure issues - I'm hooping there is a simpler way.
So far I have this for my identifiers columns - I'm aware they are wrong but hopefully will give you an idea of what I'm trying to do.
<td>{{data.security.identifiers.type === "fii" ? data.security.identifiers.value : ""}}</td>
<td>{{data.security.identifiers.type === "isin" ? data.security.identifiers.value : ""}}</td>
<td>{{data.security.identifiers.type === "cusip" ? data.security.identifiers.value : ""}}</td>
I can understand what do you want to do, the below code could work like you expect.
<td>{{data.security.identifiers.filter(function(v){return v.type == 'fii'})[0].value}}</td>
And to improve you can create a function to do the filter (probably in the Controller or Service):
$scope.identifierFilter = function(type) {
var filtered = this.data.security.identifiers.filter(function(v) {
return v.type == type;
});
return filtered && filtered[0] ? filtered[0].value : '';
};
and in the html
<td>{{identifierFilter('fii')}}</td>
I'm look at your example, I think the above code would work.But If you can change your JSON structor it will be more better and easy.
"identifiers":{
fii : 'dfdfdf',
isin : '32453452',
cusip: '48125D886'
}
html can simple like
<td>{{data.security.identifiers.fii}}</td>
And if you want to do this transform, I can give you further answer.
with could help
I update your example, sorry about some syntax error about above code.
please check: https://plnkr.co/edit/NgvJKrfOGmKHfOap08xU?p=preview
This is reconstructor data before template use.It's better if the data structor can change, choice which you like.
https://plnkr.co/edit/7eHAvSaBcOiTajOomNEs?p=preview
Probably, your best option is to use a directive, or filter depending on your requirements. A directive will make your mark-up clear and you will encapsulate the functionality you need. For example.
<table border="1" style="width:100%">
<tr>
<th>Entity</th>
<th>SecurityID</th>
<th>Security1</th>
<th>Security2</th>
<th>Security3</th>
<th>date</th>
</tr>
<tr ng-repeat="data in JSONData">
<td>{{data.entity}}</td>
<td>{{data.security.securityID}}</td>
<td><identifier identifiers="data.security.identifiers" render-type="fii"></identifier></td>
<td><identifier identifiers="data.security.identifiers" render-type="isin"></identifier></td>
<td><identifier identifiers="data.security.identifiers" render-type="cusip"></identifier></td>
<td>{{data.date}}</td>
</tr>
</table>
The plunker:
https://plnkr.co/edit/6VJuQob1jfDzsR8XPKKM?p=preview
Hope this helps.
Data come from db , and this html element is a ng-repeat
{{count}}
My Question
How can i show if else condition that,
If count is null (nothing count value) I would show 0 (count value should be zero) , else show original count value
I hope there are solution like {{count if '' else ''}}
You could have have logic in your view with {{count || 0}} or {{ count ? count : 0 }} but this makes maintainability more difficult and duplicates logic.
A better option would be to create a custom filter. This will allow you to define you condition in a single place and makes it re-usable in many directives but also testable.
.filter('isEmpty', function() {
return function (data) {
return (data === null || data === undefined) ? 0 : data;
}
});
And you would use it like
{{item | isEmpty}}
See fiddle: http://jsfiddle.net/fhfsex4v/2/
EDIT: Here's the docs for filter that will explain what its doing and also how to pass optional extra parameters into your filters and other cool stuff.
https://docs.angularjs.org/guide/filter
How about {{ count ? count : 0 }}
If I have an expression {{ x }} and x is undefined or null, then how can I display a placeholder for it?
I provided one solution in my answer, but I would like to know what other ways there are.
Maybe, also for placeholder for promises.
{{ counter || '?'}}.
Just pure javascript. || can be used as default value. Since it would be different empty messages in each, a generalized directive would not be suitable for many cases.
If you want to apply a different class to empty ones, that's also built-in:
<div ng-class="{empty: !counter}" ng-bind="counter || ?"></div>
I would do it like this, but maybe there is a better way:
angular.module('app').filter('placeholdEmpty', function(){
return function(input){
if(!(input == undefined || input == null)){
return input;
} else {
return "placeholder";
}
}
});
and then use {{ x | placeholdEmpty}}
I do it with ng-show, like this:
<strong>{{username}}</strong>
<span class="empty" ng-show="!username">N/A</span>
Sure, it adds a lot more elements to my view that I might be able to handle differently. I like though how easy it is to clearly see where my placeholder/empty values are, and I can style them differently as well.
Implement default filter:
app.filter('default', function(){
return function(value, def) {
return (value === undefined || value === null? def : value);
};
});
And use it as:
{{ x | default: '?' }}
The advantage of the filter solution over {{ x || '?'}} is that you can distinguish between undefined, null or 0.
Implementing default-ish filters works, but if you're using only numbers you can use angular's own number filter
If the input is null or undefined, it will just be returned. If the
input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or
'-∞' is returned, respectively. If the input is not a number an empty
string is returned.
{{ (val | number ) || "Number not provided"}}
How can i get a reversed array in angular?
i'm trying to use orderBy filter, but it needs a predicate(e.g. 'name') to sort:
<tr ng-repeat="friend in friends | orderBy:'name':true">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
<tr>
Is there a way to reverse original array, without sorting.
like that:
<tr ng-repeat="friend in friends | orderBy:'':true">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
<tr>
I would suggest using a custom filter such as this:
app.filter('reverse', function() {
return function(items) {
return items.slice().reverse();
};
});
Which can then be used like:
<div ng-repeat="friend in friends | reverse">{{friend.name}}</div>
See it working here: Plunker Demonstration
This filter can be customized to fit your needs as seen fit. I have provided other examples in the demonstration. Some options include checking that the variable is an array before performing the reverse, or making it more lenient to allow the reversal of more things such as strings.
This is what i used:
<alert ng-repeat="alert in alerts.slice().reverse()" type="alert.type" close="alerts.splice(index, 1)">{{$index + 1}}: {{alert.msg}}</alert>
Update:
My answer was OK for old version of Angular.
Now, you should be using
ng-repeat="friend in friends | orderBy:'-'"
or
ng-repeat="friend in friends | orderBy:'+':true"
from https://stackoverflow.com/a/26635708/1782470
Sorry for bringing this up after a year, but there is an new, easier solution, which works for Angular v1.3.0-rc.5 and later.
It is mentioned in the docs:
"If no property is provided, (e.g. '+') then the array element itself is used to compare where sorting". So, the solution will be:
ng-repeat="friend in friends | orderBy:'-'" or
ng-repeat="friend in friends | orderBy:'+':true"
This solution seems to be better because it does not modify an array and does not require additional computational resources (at least in our code). I've read all existing answers and still prefer this one to them.
Simple solution:- (no need to make any methods)
ng-repeat = "friend in friends | orderBy: reverse:true"
You can reverse by the $index parameter
<tr ng-repeat="friend in friends | orderBy:'$index':true">
You can just call a method on your scope to reverse it for you, like this:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.angularjs.org/1.0.5/angular.min.js"></script>
<script>
angular.module('myApp', []).controller('Ctrl', function($scope) {
$scope.items = [1, 2, 3, 4];
$scope.reverse = function(array) {
var copy = [].concat(array);
return copy.reverse();
}
});
</script>
</head>
<body ng-controller="Ctrl">
<ul>
<li ng-repeat="item in items">{{item}}</li>
</ul>
<ul>
<li ng-repeat="item in reverse(items)">{{item}}</li>
</ul>
</body>
</html>
Note that the $scope.reverse creates a copy of the array since Array.prototype.reverse modifies the original array.
if you are using 1.3.x, you can use the following
{{ orderBy_expression | orderBy : expression : reverse}}
Example List books by published date in descending order
<div ng-repeat="book in books|orderBy:'publishedDate':true">
source:https://docs.angularjs.org/api/ng/filter/orderBy
If you are using angularjs version 1.4.4 and above,an easy way to sort is using the "$index".
<ul>
<li ng-repeat="friend in friends|orderBy:$index:true">{{friend.name}}</li>
</ul>
view demo
When using MVC in .NET with Angular you can always use OrderByDecending() when doing your db query like this:
var reversedList = dbContext.GetAll().OrderByDecending(x => x.Id).ToList();
Then on the Angular side, it will already be reversed in some browsers (IE). When supporting Chrome and FF, you would then need to add orderBy:
<tr ng-repeat="item in items | orderBy:'-Id'">
In this example, you'd be sorting in descending order on the .Id property. If you're using paging, this gets more complicated because only the first page would be sorted. You'd need to handle this via a .js filter file for your controller, or in some other way.
You can also use .reverse(). It's a native array function
<div ng-repeat="friend in friends.reverse()">{{friend.name}}</div>
That's because you are using JSON Object. When you face such problems then change your JSON Object to JSON Array Object.
For Example,
{"India":"IN","America":"US","United Kingdon":"UK"} json object
[{"country":"India","countryId":"IN"},{"country":"America","countryId":"US"},{"country":"United Kingdon","countryId":"UK"}]
The orderBy filter performs a stable sorting as of Angular 1.4.5. (See the GitHub pull request https://github.com/angular/angular.js/pull/12408.)
So it is sufficient to use a constant predicate and reverse set to true:
<div ng-repeat="friend in friends | orderBy:0:true">{{friend.name}}</div>
I found something like this, but instead of array i use objects.
Here is my solution for objects:
Add custom filter:
app.filter('orderObjectBy', function() {
return function(items, field, reverse){
var strRef = function (object, reference) {
function arr_deref(o, ref, i) {
return !ref ? o : (o[ref.slice(0, i ? -1 : ref.length)]);
}
function dot_deref(o, ref) {
return !ref ? o : ref.split('[').reduce(arr_deref, o);
}
return reference.split('.').reduce(dot_deref, object);
};
var filtered = [];
angular.forEach(items, function(item) {
filtered.push(item);
});
filtered.sort(function (a, b) {
return (strRef(a, field) > strRef(a, field) ? 1 : -1);
});
if(reverse) filtered.reverse();
return filtered;
};
});
Which can then be used like
<div ng-repeat="(key, value) in items | orderObjectBy:'field.any.deep':true">
If you need old browser support, you will need to define the reduce function (this is only available in ECMA-262 mozilla.org)
// Production steps of ECMA-262, Edition 5, 15.4.4.21
// Reference: http://es5.github.io/#x15.4.4.21
if (!Array.prototype.reduce) {
Array.prototype.reduce = function(callback /*, initialValue*/) {
'use strict';
if (this == null) {
throw new TypeError('Array.prototype.reduce called on null or undefined');
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function');
}
var t = Object(this), len = t.length >>> 0, k = 0, value;
if (arguments.length == 2) {
value = arguments[1];
} else {
while (k < len && !(k in t)) {
k++;
}
if (k >= len) {
throw new TypeError('Reduce of empty array with no initial value');
}
value = t[k++];
}
for (; k < len; k++) {
if (k in t) {
value = callback(value, t[k], k, t);
}
}
return value;
};
}
I had gotten frustrated with this problem myself and so I modified the filter that was created by #Trevor Senior as I was running into an issue with my console saying that it could not use the reverse method. I also, wanted to keep the integrity of the object because this is what Angular is originally using in a ng-repeat directive. In this case I used the input of stupid (key) because the console will get upset saying there are duplicates and in my case I needed to track by $index.
Filter:
angular.module('main').filter('reverse', function() {
return function(stupid, items) {
var itemss = items.files;
itemss = itemss.reverse();
return items.files = itemss;
};
});
HTML:
<div ng-repeat="items in items track by $index | reverse: items">
Im adding one answer that no one mentioned. I would try to make the server do it if you have one. Clientside filtering can be dangerous if the server returns a lot of records. Because you might be forced to add paging. If you have paging from the server then the client filter on order, would be in the current page. Which would confuse the end user. So if you have a server, then send the orderby with the call and let the server return it.
Useful tip:
You can reverse you're array with vanilla Js: yourarray .reverse()
Caution: reverse is destructive, so it will change youre array, not only the variable.
I would sugest using array native reverse method is always better choice over creating filter or using $index.
<div ng-repeat="friend in friends.reverse()">{{friend.name}}</div>
Plnkr_demo.