I have a triple nested ng-repeat which I am tyring to allow the user to delete items inside when they are displayed using a simple .splice. I can send the index of the highest level item, the $parent.$index for the next level down, But on the third level down I need somehting like $parent.$parent.$index to pass the index of the correct item int he json object to delete, can I do something like this?
Here's what I tried
ng-click="deleteMe($parent.$parent.$index, $parent.$index, $index)
How could I properly send the index of the highest parent? Thanks!
Use ng-init please see more here https://docs.angularjs.org/api/ng/directive/ngInit
or sample demo here http://plnkr.co/edit/qRJlAzPfwaZr8NENs7K0?p=preview
<body ng-controller="MainCtrl">
<div ng-repeat="father in data" ng-init="indxFirst = $index">
<h3>{{father.person}}</h3>
<ul>
<li ng-repeat="kids in father.kids" ng-init="indxSecond = $index">{{kids.name}}
<p ng-repeat="color in kids.colors" ng-init="indxThird=$index">Colour: {{color.color}}
<button ng-click="delete(indxFirst, indxSecond, indxThird)">delete</button>
<p>
</li>
</ul>
</div>
</body>
Related
I am a newbie and i am trying few angular js examples but when create 2 div elements and try to run the angular js program for it. the initialized array is getting printed for the second div and it is not getting printed for the first div when i am using ng-repeat. Can anyone tell me why it is happening. I am not able to see any difference between the way 2 arrays have been initialized. The code is below.
<html data-ng-app>
<head>
<title>Angular js</title>
</head>
<body>
<input type="text" data-ng-model="name">{{name}}
<div class="container" data-ng-init="namess=['Hello','There','God','There']">
<h3>Looping with the ng-repeat Directive</h3>
<h4>Data to loop through is initialized using ng-init</h4>
<ul>
<li data-ng-repeat="Personname in namess">{{Personname}}</li>
</ul>
</div>
<div class="container" data-ng-init="names=['Dave','Napur','Heedy','Shriva']">
<h3>Looping with the ng-repeat Directive</h3>
<h4>Data to loop through is initialized using ng-init</h4>
<ul>
<li data-ng-repeat="name in names">{{name}}</li>
</ul>
</div>
</body>
<footer>
<script type="text/javascript" src="angular.min.js"></script>
</footer>
</html>
The result i am getting is as below
Looping with the ng-repeat Directive
Data to loop through is initialized using ng-init
Looping with the ng-repeat Directive
Data to loop through is initialized using ng-init
Dave
Napur
Heedy
Shriva
If you look in your console you will see an error about duplicates on the first ng-repeat. Because you have "There" in your array twice you need to add a track by to your ng-repeat. Try replacing it with this:
<li data-ng-repeat="Personname in namess track by $index">{{Personname}}</li>
There are duplicate entries in your first array and if you check the console you can see the error "Error: [ngRepeat dupes]". Angular ngRepeat doesn't allow duplicate values. Check the following link for the details https://docs.angularjs.org/error/ngRepeat/dupes .
To fix, either remove the duplicate entry (There) or use following:
<li data-ng-repeat="Personname in namess track by $index">{{Personname}}</li>
data-ng-repeat="Personname in namess track by $index, this should fix the problem.
I am trying to display a JSON response in a table using ng-repeat. The problem is that not all objects recieved are the same. All of them have a date, short message and long message. There are also ones with an additional value list, differing in length. This list should be diplayed underneath the long message within its own table or list. I use the alert.slice().reverse() because I want the newest entries to be on top. The new objects are inserted using .push({values}).
<tbody class="AlTbody" ng-repeat="alerts in alerts.slice().reverse()" ng-class="className">
<tr class="Altr Aldate">
<td ng-show="{{alerts.Date}}"><b>{{alerts.Date}}:</b>
</td>
</tr>
<tr class="Altr Alshort " ng-click="toggleDetail($index)">
<td>{{alerts.S}}</td>
</tr>
<tr class="Altr " ng-show="activePosition == $index">
<td class="msgL">{{alerts.L}}
<!-- 1) <p ng-show="{{item.List}}"><br><ul><li>Previous values:</li> <li ng-repeat="vals in ValueList">{{vals.value}}</li></ul> </p>-->
<!-- 2) <p ng-show="{{List.txt}}"> <br><ul><li>Previous values:</li> <li ng-repeat="List in alerts.List">{{List.txt}}</li></ul> </p>-->
</td>
</tr>
</tbody>
I already tried two approaches as seen in the code. The first one displayed the list correct however it was displayed underneath every long message instead of only the one it belongs to. I used a new variable.
var l=valList.length;
scope.List=true;
while(l>-1){
scope.ValueList.push({value: valList[l]});
l--;
}
The second approach did not work at all because I could not find an index.
var l=valList.length;
var indexV= jQuery.inArray(currdate,scope.alerts.Date);
while(l>-1){
scope.alerts[indexV].List.push({txt: valList[l]});
l--;
}
edit:
This is the current output. There you can see two objects( date, short message and long message) and both of them have the previous values section. However only the upper object is supposed to diplay the list of previous values.
What you are trying to achieve is entirely possible, my advice is to start at a known point and work from there.
I have put together a jsfiddle to show you how nested ng-repeats will work. try and work from that point. As a side note it looks like your JSON structure is overly complex, if you can simplify that down I would.
https://jsfiddle.net/roscorcoran/wyu7tgxm/
<div ng-app="App" ng-controller="Ctrl1">
<div ng-repeat="alert in alerts">
<a ng-if="alert.Date">{{alert.Date}}</a>
<p ng-repeat="val in alert.L.vals">
<a ng-if="val && val.value">{{val.value}}</a>
</p>
<p ng-repeat="item in alert.List">
<a ng-if="item && item.txt">{{item.txt}}</a>
</p>
</div>
</div>
You can try to add a ng-if statement inside the ng-repeat loop:
<p ng-if="{{values.list}}"><br><ul><li>Previous values:</li> <li ng-repeat="vals in values.list">{{vals.value}}</li></ul> </p>-->
Okay so this works for me now. It still always displays "Previous Values:" but the values only display when they actually belong to the message.
<ul ng-if="alerts.List.vals"><li>Previous values:</li> <li ng-repeat="val in alerts.List.vals" >{{val.value}}</li></ul>
This might not be the best and most elegant solution but it works.
if(valList){
scope.alerts.push({Date:currdate,S:msgSn,L:msgLn, List:{ vals:[{value:valList[0]},{value:valList[2]},{value:valList[4]},{value:valList[6]}] } });
}else{
scope.alerts.push({Date:currdate,S:msgSn,L:msgLn });
}
I only display the even indexes of the value array because the list of values was a string which I split and every uneven entry is "):" which I don't need to display.
Hi guys i need a quick response, sorry for my lack of english but here is the problem:
I'm doing ng-repeat on a JSON object i recieve from the API. The object has listin it etc. and the Json object has PLACE value. Place is a int that gives me the position where to put the object, and how to put it in a LIST!
so i do the ng-repeat="s in object" and now i need the s.PLACE value to Filter the objects. How do i do that?
<div class="some class" ng-repeat="s in Object| limitTo:6:0 ">
<li>{{s.Name}}</li>
</div>
example, just how mI supposed to tell him, IF PLACE IS == 1 SKIP don ng-Repeat item, or when PLACE==2 put it in the last place. Is this possible with ng-repeat?
<div class="some class" ng-repeat="s in Object| limitTo:6:0 ">
<li ng-if="s.PLACE > 1">{{s.Name}}</li>
</div>
So i found out i can use ng-if for stuff like this!
I have a products variable, which holds a nested array of hierarchical products, such as:
Product
- cat_id: 1
- name: Some Product
- Children
- Child Product 1
- Child Product 2
- Children
- I can also have more children here
- And another
- Child 3
Product 2
- cat_id: 2
- name: Some other Product
- Children
- A child product
- another
I also have another variable which is an array of products that have been purchased.
What I want to do is to display the full product list as above, but if the user has purchased it, to apply a class.
Here's where I'm at so far:
<ul>
<li ng-repeat="product in all_products track by product.cat_id">
{{ product.cat_name }}
<ul ng-if="product.children.length>0">
<li ng-repeat="l1_child_product in product.children track by l1_child_product.cat_id">
{{ l1_child_product.cat_name }}
<ul ng-if="l1_child_product.children.length>0">
<li ng-repeat="l2_child_product in l1_child_product.children track by l2_child_product.cat_id">
{{ l2_child_product.cat_name }}
</li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
What I want to do is for each is to apply the class, if the contents of the second array, contains the current product's cat_id, for instance:
<li ng-repeat="product in all_products track by product.cat_id" ng-class="foreach(otherarray as owned){ if(owned.cat_id==product.cat_id){ 'some_class' } }">
I'm still very new to Angular so i'd like to know the proper way of achieving this.
I'm currently porting my application from being purely server side with a static front end, to Angular. I was able to perform this sort of logic extremely quickly using a few nested for-loops with conditional statements in my old app.
However, with Angular, this seems to cause the application to grind down to a very slow pace.
I've heard of dirty-checking, which Angular uses and I think I'm hitting the bottlenecks that occur as a result as my datasets are generally fairly large (around 250 products, with around 40 purchases), but with up to 20 users being shown on a page. What's a good way of avoiding these performance issues when using Angular?
Updated
Here's the code I'm using at the moment:
<div class="row" ng-repeat="user in ::users">
<script type="text/ng-template" id="product_template.html">
{{ ::product.cat_name }}
<ul ng-if="product.children">
<li ng-repeat="product in ::product.children track by product.cat_id"
ng-include="'product_template.html'"></li>
</ul>
</script>
<ul>
<li ng-repeat="product in ::all_products track by product.cat_id"
ng-include="'product_template.html'"></li>
</ul>
<table>
<tr ng-repeat="licence in ::user.licences">
<td>{{::licence.product.cat_name}}</p></td>
<td>{{::licence.description}}</td>
<td>{{::licence.start_date}}</td>
<td>{{::licence.end_date}}</td>
<td>{{::licence.active}}</td>
</tr>
</table>
</div>
This gives the desired output of:
Iterate over the users
Iterate over ALL of the products available
Display a list of all of their purchases (licences)
However, it's incredibly slow. I just timed the page load, and it took 32 seconds to parse all of the data and display it (the data was available after around 100ms).
I'm using the new :: syntax to prevent lots of two-way bindings but this doesn't seem to improve the speed at all.
Any ideas?
Your question is 2 parts:
How do I display products and their children recursively?
In an efficient way, how do I add a class if a product has been purchased?
Displaying Products and their Children
This has already answered well by a previous question on Rending a Tree View with Angular.
Efficiently adding a Purchased class
The inefficiency you currently have is caused from looking through otherarray for every single product.
There are various solutions on how to improve upon this but I think the easiest change for you would to make would be to use an {} instead of an array to track purchased products.
{ cat_id: true }
For more information on why using an Object or Hash is faster looking at this question on Finding Matches between Arrays.
Combined Solution
Displaying Products and their Children
<script type="text/ng-template" id="product_template.html">
{{ product.cat_name }}
<ul ng-if="product.children">
<li ng-repeat="product in product.children"
ng-include="'product_template.html'"
ng-class="{ purchased : product.purchased }"></li>
</ul>
</script>
<ul ng-app="app" ng-controller="ProductCtrl">
<li ng-repeat="product in all_products"
ng-include="'product_template.html'"
ng-class="{ purchased : purchasedProducts[product.cat_id] }"></li>
</ul>
Effiecntly adding a Purchased class aka. otherarray -> purchasedProducts object
I don't know exactly where otherarray is being constructed but a simple conversion would go as follows:
var purchasedProducts = {};
for (var i = 0; i < otherarray.length; i++) {
var cat_id = otherarray[i];
purchasedProducts[cat_id] = true;
}
Remember that ng-class can be a function call.
Starting with Angular 1.3, there is native Bind Once support. when iterating over a large number of items, you can eliminate the watchers on static elements which will not change.
For Example:
<li ng-repeat="product in ::all_products track by product.cat_id">
Will iterate through the all_products array once to populate the ngRepeat, but will not continue to be bound to $watch for change tracking. Smart use of :: can drastically improve performance.
Also, converting ng-class= to a function instead of an inline expression evaluation can improve performance and give you greater control over your output.
I am trying to print the count of elements filtered through a condition in AngularJS.
I am using ng-repeat to loop over collection and filter it to get counts and it works fine when there is value in it. However, when the filter returns empty result, Angular doesn't render the element and hence, I can't get it to display 0 count.
http://plnkr.co/edit/KNVwf2Yckxf1Qcyzcmea?p=preview
<div ng-repeat="i in iArr|filter:i.name='tim'">{{i.vals.length}}</div>
Does anyone have a clue to make it work in simple fashion.
Edit:
The question How to show a message when filter returns nothing in ng-repeat - AngularJS has a reply which actually solved my question but I don't know how. I am wondering if there is a very simple way to do it.
From that answer:
<select ng-model="shade" ng-options="shade for shade in shades"></select><br>
<ul>
<li ng-repeat="c in filteredColors = (colors | filter:shade)">{{c.name}}</li>
</ul>
<div ng-show="!filteredColors.length">No colors available</div>
The key is in c in filteredColors = (colors | filter:shade). The array result of the filter expression colors | filter:shade is being set to filteredColors, which then becomes available on the $scope object. Because of this, it can be used elsewhere in that controller scope. This is why it can be checked for its length to see if there are no colors.
Here is a working plnkr with solution and some extra
http://plnkr.co/edit/eOmHhR1VWjfYzHYqiEY1?p=preview
<body ng-controller="MainCtrl">
<label><input type="text" ng-model="search.vals">vals</label>
<label><input type="text" ng-model="search.name">name</label>
<div ng-repeat="i in filteredArr = (iArr | filter:search)">{{i.vals}} | {{i.name}}</div>
<div ng-if="!filteredArr.length">0</div>
</body>