Angular js custom filter to array - angularjs

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.

Related

How can i conditionally display an element using AngularJS

I want to display an element conditionally based on the value of another parameter PaymentTypeid. After setting the condition as below the element Payment Channel is not rendering in the UI:
<tr ng-init="paymentMode='BANK CABS'" ng-if="json.name == 'paymentTypeId' && json.property == '1'">
<td><strong>{{ 'label.heading.paymentchannel' | translate }}:</strong></td>
<td ><span >{{paymentMode}} </span></td>
</tr>
However when i refactor the markup as below the element is showing as :
<tr ng-init="paymentMode='BANK CABS'">
<td><strong>{{ 'label.heading.paymentchannel' | translate }}:</strong></td>
<td ><span >{{paymentMode}} </span></td>
</tr>
PaymentTypeId is in a json array defined as follows in the controller:
scope.details = {};
resourceFactory.auditResource.get({templateResource: routeParams.id}, function (data) {
scope.details = data;
scope.details.paymentMode="";
scope.commandAsJson = data.commandAsJson;
var obj = JSON.parse(scope.commandAsJson);
scope.jsondata = [];
_.each(obj, function (value, key) {
scope.jsondata.push({name: key, property: value});
});
});
In the view PaymentTypeid renders as :
<table class="table" data-ng-show="details.commandAsJson" data-anchor>
<tbody>
<tr data-ng-repeat="json in jsondata">
<td class="width20"><strong> {{json.name}}</strong></td>
<td class="width80">{{json.property}}</td>
</tr>
</tbody>
</table>
Any insight on what i might be getting wrong. Im not entirely sure between using ng-if/ng-show or whether im setting json.property correctly.
Assuming that you have knowledge of scope in AngularJS.
There is a difference between using ng-if and ng-show. Whenever you use ng-if , it creates it own child scope. and you can manage it in custom directive that deals with its child scope (child scope is not available in controller unless you write your code in a way, that will make it available in controller) and you can hack the scope to use it in controller too. But that is not the case in ng-show.
When you use ng-show it will not remove your HTML from the DOM tree but if you use ng-if it will also remove your html from DOM tree. (To assist your confusion which one to use)
You have a scope issue here , if i'm getting it right. Use ng-show and it will work.
<div ng-show="condition">
your html markup
</div>

how to iterate json data using ng-repeat in angularjs

how to iterate json data using ng-repeat in angularjs
{
"CSS Corp":{
"COE":{"win_loss":[6,4]},
"YNOS":{"win_loss":[5,5]},
"ESTEE":{"win_loss":[10,0]},
"ELC":{"win_loss":[8,2]}
},
"SSSPL":{
"PEG":{"win_loss":[0,10]},
"ARUBA":{"win_loss":[2,8]},
"SALES":{"win_loss":[1,9]},
"MARKETING":{"win_loss":[7,3]}
},
}
Your question is very broad. You will first have to attach those JSON data to the scope of your controller and expose it to the template through a variable myData. Assuming you know how to do that, the use of ng-repeat becomes very trivial (add more columns or rows to fit your dataset):
<table>
<thead>
<tr><th>Header 1</th></tr>
</thead>
<tbody>
<tr ng-repeat="item in myData">
<td>{{ item }}</td>
</tr>
</tbody>
</table>
Use ng-repeat
Syntax : <tr ng-repeat="value in container">
Assuming that you have a array of JSON object in your JS as below,
var arrayObject = [
"CSS Corp":{
"COE":{"win_loss":[6,4]},
"YNOS":{"win_loss":[5,5]},
"ESTEE":{"win_loss":[10,0]},
"ELC":{"win_loss":[8,2]}
},
"SSSPL":{
"PEG":{"win_loss":[0,10]},
"ARUBA":{"win_loss":[2,8]},
"SALES":{"win_loss":[1,9]},
"MARKETING":{"win_loss":[7,3]}
}
];
Then your view should iterate as below,
<div ng-repeat="company in arrayObject">
{{company}} // use whatever you want to print
</div>

Hide table rows in angular Js

I have a table, I am already given it CSS using ng-class if they satisfy a condition. Now I want to show only those rows who satisfy the same condition on a button click. I have wrote a controller which checks if the data received is within 24 hours are not and marks the data cell. Until this it's working.Now I need to add a button and show only the row which has this td marked as not received in time.
<tbody>
<tr ng-repeat ="data in log">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td ng-class ="{'data-notreceived' : dataNotReceived('data.receivedTime')}">{{data.receivedTime
}}
</tbody>
</table>
I think something like this should work. Basically, clicking the button will toggle between showing all or only the items marked as 'data not received'.
<tbody>
<tr ng-repeat ="data in log" ng-show="showAll || dataNotReceived(data.receivedTime)">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td ng-class ="{'data-notreceived' : dataNotReceived('data.receivedTime')}">{{data.receivedTime}}
</tr>
</tbody>
// in controller
$scope.showAll = true;
$scope.onButtonClick = function() {
$scope.showAll = !$scope.showAll;
return false;
}
From the information provided in question what I can say is: Use ng-show to show rows based on your condition.
<tr ng-show ="your_condition">
You could also use an ng-if rather than ng-show. See the differences here.
Really depends on how often the hide/show toggle needs to happen.
<tbody>
<tr ng-repeat="data in log" ng-if="showLast24Hrs(data.ReceivedTime)">
<td>{{data.UniqueId}}</td>
<td>{{data.Name}}</td>
<td>{{data.ReceivedTime}}</td>
</tbody>
and then in the controller,
$scope.showLast24Hrs = function(receivedTime){
if($scope.isLast24Hours) {
return receivedTime < 200; // Write your less than 24 hours check here
}
return true;
}
I wrote this demo on Codepen. Hope that helps.

turn off re-sorting in angularJS while editing

I have an AngularJS app that lists a bunch of items in a table. Like this:
<table class='unstyled tmain'>
<tr>
<td ng-click='setSort($event)'>X</td>
<td ng-click='setSort($event)'>Desc</td>
<td ng-click='setSort($event)'>created</td>
<td> </td>
</tr>
<tr ng-repeat="item in items | orderBy:itemNormalizationFunction:sortReverse">
<td><input type='checkbox' ng-model='item.done'
ng-click='onCheckedChanged(item)'/></td>
<td><div edit-in-place="item.text"
on-save="updateItemText(value,previousValue,item)"></div></td>
<td><span class='foo'>{{item.created | dateFormatter}}</span></td>
</tr>
</table>
The table headers are clickable to set the sort order. The cell in the 2nd column in each data row is editable "in place" - if you click on the text it gets replaced with an input textbox, and the user can edit the text. I have a little directive enabling that. This all works.
The problem comes in while editing. Suppose I have it set to sort by "description" (the 2nd column). Then if I edit the description (via the edit-in-place directive), as I am typing in the input box, the sort order changes. If I change the first few characters, then angular re-sorts and the item is no longer under my cursor. Nor is it even focused. I have to go hunting through the list to find out where it got re-sorted to, then I can re-focus, and resume typing.
This is kinda lame.
What I'd like to do is tell angular to (a) stop re-sorting while I am keying in the input box, or (b) sort on a separate (not-displayed) index value that preserves the ordering before the edit began. But I don't know how to do either of those. Can anyone give me a hint?
I know this is sort of complicated so I'll try to put together a plunkr to show what's happening.
This is the plunkr that shows how I solved the problem.
http://embed.plnkr.co/eBbjOqNly2QFKkmz9EIh/preview
You can create custom filter and call that only when necessary. Example when you click on 'Grid header' for sorting or after dynamically adding/removing values to array, or simply click of a button(Refresh Grid)
You need to dependency Inject Angular filter and sort filter
angular
.module('MyModule')
.controller('MyController', ['filterFilter', '$filter', MyContFunc])
function ExpenseSubmitter(funcAngularFilter, funcAngularFilterOrderBy) {
oCont = this;
oCont.ArrayOfData = [{
name: 'RackBar',
age: 24
}, {
name: 'BamaO',
age: 48
}];
oCont.sortOnColumn = 'age';
oCont.orderBy = false;
var SearchObj = {
name: 'Bama'
};
oCont.RefreshGrid = function() {
oCont.ArrayOfData = funcAngularFilter(oCont.ArrayOfData, SearchObj);
oCont.ArrayOfData = funcAngularFilterOrderBy('orderBy')(oCont.ArrayOfData, oCont.sortOnColumn, oCont.orderBy);
}
}
and call in HTML something like:
<table>
<thead>
<tr>
<th ng-click="oCont.sortOnColumn = 'age'; oCont.RefreshGrid()">Age</th>
<th ng-click="oCont.sortOnColumn = 'name'; oCont.RefreshGrid()">Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="val in oCont.ArrayOfData">
<td>{{val.age}}</td>
<td>{{val.name}}</td>
</tr>
</tbody>
</table>

How to use ng-repeat without an html element

I need to use ng-repeat (in AngularJS) to list all of the elements in an array.
The complication is that each element of the array will transform to either one, two or three rows of a table.
I cannot create valid html, if ng-repeat is used on an element, as no type of repeating element is allowed between <tbody> and <tr>.
For example, if I used ng-repeat on <span>, I would get:
<table>
<tbody>
<span>
<tr>...</tr>
</span>
<span>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</span>
<span>
<tr>...</tr>
<tr>...</tr>
</span>
</tbody>
</table>
Which is invalid html.
But what I need to be generated is:
<table>
<tbody>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
<tr>...</tr>
</tbody>
</table>
where the first row has been generated by the first array element, the next three by the second and the fifth and sixth by the last array element.
How can I use ng-repeat in such a way that the html element to which it is bound 'disappears' during rendering?
Or is there another solution to this?
Clarification: The generated structure should look like below. Each array element can generate between 1-3 rows of the table. The answer should ideally support 0-n rows per array element.
<table>
<tbody>
<!-- array element 0 -->
<tr>
<td>One row item</td>
</tr>
<!-- array element 1 -->
<tr>
<td>Three row item</td>
</tr>
<tr>
<td>Some product details</td>
</tr>
<tr>
<td>Customer ratings</td>
</tr>
<!-- array element 2 -->
<tr>
<td>Two row item</td>
</tr>
<tr>
<td>Full description</td>
</tr>
</tbody>
</table>
As of AngularJS 1.2 there's a directive called ng-repeat-start that does exactly what you ask for. See my answer in this question for a description of how to use it.
Update: If you are using Angular 1.2+, use ng-repeat-start. See #jmagnusson's answer.
Otherwise, how about putting the ng-repeat on tbody? (AFAIK, it is okay to have multiple <tbody>s in a single table.)
<tbody ng-repeat="row in array">
<tr ng-repeat="item in row">
<td>{{item}}</td>
</tr>
</tbody>
If you use ng > 1.2, here is an example of using ng-repeat-start/end without generating unnecessary tags:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script>
angular.module('mApp', []);
</script>
</head>
<body ng-app="mApp">
<table border="1" width="100%">
<tr ng-if="0" ng-repeat-start="elem in [{k: 'A', v: ['a1','a2']}, {k: 'B', v: ['b1']}, {k: 'C', v: ['c1','c2','c3']}]"></tr>
<tr>
<td rowspan="{{elem.v.length}}">{{elem.k}}</td>
<td>{{elem.v[0]}}</td>
</tr>
<tr ng-repeat="v in elem.v" ng-if="!$first">
<td>{{v}}</td>
</tr>
<tr ng-if="0" ng-repeat-end></tr>
</table>
</body>
</html>
The important point: for tags used for ng-repeat-start and ng-repeat-end set ng-if="0", to let not be inserted in the page. In this way the inner content will be handled exactly as it is in knockoutjs (using commands in <!--...-->), and there will be no garbage.
You might want to flatten the data within your controller:
function MyCtrl ($scope) {
$scope.myData = [[1,2,3], [4,5,6], [7,8,9]];
$scope.flattened = function () {
var flat = [];
$scope.myData.forEach(function (item) {
flat.concat(item);
}
return flat;
}
}
And then in the HTML:
<table>
<tbody>
<tr ng-repeat="item in flattened()"><td>{{item}}</td></tr>
</tbody>
</table>
The above is correct but for a more general answer it is not enough. I needed to nest ng-repeat, but stay on the same html level, meaning write the elements in the same parent.
The tags array contain tag(s) that also have a tags array.
It is actually a tree.
[{ name:'name1', tags: [
{ name: 'name1_1', tags: []},
{ name: 'name1_2', tags: []}
]},
{ name:'name2', tags: [
{ name: 'name2_1', tags: []},
{ name: 'name2_2', tags: []}
]}
]
So here is what I eventually did.
<div ng-repeat-start="tag1 in tags" ng-if="false"></div>
{{tag1}},
<div ng-repeat-start="tag2 in tag1.tags" ng-if="false"></div>
{{tag2}},
<div ng-repeat-end ng-if="false"></div>
<div ng-repeat-end ng-if="false"></div>
Note the ng-if="false" that hides the start and end divs.
It should print
name1,name1_1,name1_2,name2,name2_1,name2_2,
I would like to just comment, but my reputation is still lacking. So i'm adding another solution which solves the problem as well. I would really like to refute the statement made by #bmoeskau that solving this problem requires a 'hacky at best' solution, and since this came up recently in a discussion even though this post is 2 years old, i'd like to add my own two cents:
As #btford has pointed out, you seem to be trying to turn a recursive structure into a list, so you should flatten that structure into a list first. His solution does that, but there is an opinion that calling the function inside the template is inelegant. if that is true (honestly, i dont know) wouldnt that just require executing the function in the controller rather than the directive?
either way, your html requires a list, so the scope that renders it should have that list to work with. you simply have to flatten the structure inside your controller. once you have a $scope.rows array, you can generate the table with a single, simple ng-repeat. No hacking, no inelegance, simply the way it was designed to work.
Angulars directives aren't lacking functionality. They simply force you to write valid html. A colleague of mine had a similar issue, citing #bmoeskau in support of criticism over angulars templating/rendering features. When looking at the exact problem, it turned out he simply wanted to generate an open-tag, then a close tag somewhere else, etc.. just like in the good old days when we would concat our html from strings.. right? no.
as for flattening the structure into a list, here's another solution:
// assume the following structure
var structure = [
{
name: 'item1', subitems: [
{
name: 'item2', subitems: [
],
}
],
}
];
var flattened = structure.reduce((function(prop,resultprop){
var f = function(p,c,i,a){
p.push(c[resultprop]);
if (c[prop] && c[prop].length > 0 )
p = c[prop].reduce(f,p);
return p;
}
return f;
})('subitems','name'),[]);
// flattened now is a list: ['item1', 'item2']
this will work for any tree-like structure that has sub items. If you want the whole item instead of a property, you can shorten the flattening function even more.
hope that helps.
for a solution that really works
html
<remove ng-repeat-start="itemGroup in Groups" ></remove>
html stuff in here including inner repeating loops if you want
<remove ng-repeat-end></remove>
add an angular.js directive
//remove directive
(function(){
var remove = function(){
return {
restrict: "E",
replace: true,
link: function(scope, element, attrs, controller){
element.replaceWith('<!--removed element-->');
}
};
};
var module = angular.module("app" );
module.directive('remove', [remove]);
}());
for a brief explanation,
ng-repeat binds itself to the <remove> element and loops as it should, and because we have used ng-repeat-start / ng-repeat-end it loops a block of html not just an element.
then the custom remove directive places the <remove> start and finish elements with <!--removed element-->
<table>
<tbody>
<tr><td>{{data[0].foo}}</td></tr>
<tr ng-repeat="d in data[1]"><td>{{d.bar}}</td></tr>
<tr ng-repeat="d in data[2]"><td>{{d.lol}}</td></tr>
</tbody>
</table>
I think that this is valid :)

Resources