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
<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?
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:
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?
This has already answered well by a previous question on Rending a Tree View with Angular .
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 .
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;
}
请记住,ng-class可以是函数调用。
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.