Number of watchers adding up with ng-repeat - angularjs

The below code renders tabs, sections under each tab and the content of the section. When navigating from one section to another, I notice the number of watchers are increasing (or) adding up each time.
Can any one tell what could be the reason for this. Appreciate any pointers
<ul class="nav nav-tabs">
<li ng-repeat="tab in tabList track by tab.tabId" id="{{tab.attribute}}"
ng-class="{active:selectedTab.attribute === '{{tab.attribute}}'}">
<a showtab="" href="#{{tab.attribute}}" ng-click="setSelectedTab(tab)">{{tab.displayLabel}}</a>
</li>
</ul>
<div class="tab-pane">
<div class="" ng-if="selectedTab.sectionList.length > 0">
<ul class="nav nav-pills pills-section">
<li ng-repeat="section in selectedTab.sectionList track by section.sectionId" id="{{section.attribute}}" ng-class="{active:selectedSection.attribute === '{{section.attribute}}'}">
<a showtab="" href="#{{section.attribute}}" ng-click="setSelectedSection(section)">{{section.displayLabel}}</a>
</li>
</ul>
<!-- Content of the section rendered with ng-repeat -->
<div ng-include="sectionContent"/>
</div>
</div>
The section content has the below mark up
<table>
<tbody>
<tr ng-repeat="field in selectedSection.fields track by field.fieldId">
</tr>
</tbody>
</table>

I have had similar problems before, nesting ng-repeats is never a good idea, but we are forced from time to time to do it. This is your solution to have performance benefits.
http://kamilkp.github.io/angular-vs-repeat/

Related

Allowing multiple directives to transclude in a recursive template

I am currently receiving a tree of managers and their subordinates from the back end. I'm using a recursive template to display this.
<script type="text/ng-template" id="managerTmp">
<div class="accordion">
{{user.firstName}} {{user.lastName}}
<ul class="list-group" ng-if="user.subordinates" >
<li class="list-group-item" ng-if="user.subordinates" ng-repeat="user in user.subordinates" ng-include="'managerTmp'">
</li>
</ul>
</div>
</script>
<div class="col-lg-12" ng-show="section === 5">
<uib-accordion close-others="oneAtATime" ng-show="portal.acManagers && !spinning">
<ul class="list-group" id="1q2w3e">
<li class="list-group-item" ng-repeat="user in portal.acManagers" ng-include="'managerTmp'" ></li>
</ul>
</uib-accordion>
</div>
This all works fine and I get a ul/li of the tree. However, whenever I try changing the ul/li to the angularUI accordion (uib-accordion & uib-accordion-group) i get an error saying
Error: [$compile:multidir] Multiple directives [ngInclude, uibAccordionGroup (module: ui.bootstrap.accordion)] asking for transclusion on: <uib-accordion-group class="list-group-item" ng-if="user.subordinates" ng-repeat="user in user.subordinates" ng-include="'managerTmp'" id="azqx">
I don't fully understand the issue or why angularjs does not allow this? Any help would be greatly appreciated.

ng-repeat list item is not rendering inside the anchor

So heres what the html looks like in the text editor...
<div ng-repeat="x in Result">
<a ng-href="https://domain.com/{{x.short_url}}">
<li class="viewer" id="{{x.user_id}}" style="background-image: url(https://domain.com/{{x.user_id}})">
</a>
</div>
But when its rendered in the browser it looks like this...
<a ng-href="https://domain.com/ucmzda" href="https://domain.com/ucmzda"></a>
<li class="viewer" id="b5599b09bcb3467ba3ade4e5b30721a4" style="background-image: url(https://domain.com/image/user/b5599b09bcb3467ba3ade4e5b30721a4)">
I cant figure out why the list item is not rendering inside the anchor?
<div ng-repeat="x in Result">
<a ng-href="https://domain.com/{{x.short_url}}">
<li class="viewer" id="{{x.user_id}}" style="background-image: url(https://domain.com/{{x.user_id}})"><li>
</a>
</div>
refer:
ng-repeat inserting empty anchor tags
In your case li is not closed:
It is not a good practies to use li inside a tag:
use like this
<ul ng-repeat="x in Result">
<li class="viewer" id="{{x.user_id}}" style="background-image: url(https://domain.com/{{x.user_id}})"><a ng-href="https://domain.com/{{x.short_url}}">
</a>
</li>
</ul>
Have you by any chance configured your $locationProvider to html5Mode? If yes this would cause your problems. You could force it to always go to the url by adding target="_self" to your tag. Give it a shot.**
use HTML5 so adding the target="_self" it will work

Trying to get ui.bootstrap dropdown to work

I'm trying to get a bootstrap dropdown working. I have attempted to pretty much exactly follow the code at The Angular UI page. It's not working.
I have a Plunker here. Here's the code that's not working:
<table>
<tr>
<td align="center" class="give-store-button-group dropdown">
<a href class="dropdown-toggle" dropdown-toggle="">{{backslaps[current].store}}</a>
<ul class="dropdown-menu">
<li ng-repeat="store in backslaps">
<a href>{{store.store}}</a>
</li>
</ul>
</td>
</tr>
</table>
Thank you for any help.
You need to put a container containing dropdown attribute directive.
<span class="dropdown" dropdown>
<a href class="dropdown-toggle" dropdown-toggle="">{{backslaps[current].store}}</a>
<ul class="dropdown-menu"> .... </ul>
</span>
Check this updated plunker

How can I use the same piece of html with different data in AngularJS without duplication?

I need the following:
<ul>
<li data-ng-repeat="person in row1">
<img data-ng-src="img/{{person.code}}.jpg">
<h3>{{person.name}}</h3>
<p>{{person.description}}</p>
</li>
</ul>
<ul>
<li data-ng-repeat="person in row2">
<img data-ng-src="img/{{person.code}}.jpg">
<h3>{{person.name}}</h3>
<p>{{person.description}}</p>
</li>
</ul>
but I don't want to duplicate the html - I want to be able to pass in the two different arrays (row1 and row2) to ng-include or something similar. How can I do this in AngularJS?
You can give the array of rows to another model and use ng-repeat in ul tag
In your controller:
$scope.rows = [row1, row2];
In your template:
<ul ng-repeat="row in rows">
<li ng-repeat="person in row">
<img data-ng-src="img/{{person.code}}.jpg">
<h3>{{person.name}}</h3>
<p>{{person.description}}</p>
</li>
</ul>

passing 2 $index values within nested ng-repeat

So I have an ng-repeat nested within another ng-repeat in order to build a nav menu. On each <li> on the inner ng-repeat loop I set an ng-click which calls the relevant controller for that menu item by passing in the $index to let the app know which one we need. However I need to also pass in the $index from the outer ng-repeat so the app knows which section we are in as well as which tutorial.
<ul ng-repeat="section in sections">
<li class="section_title {{section.active}}" >
{{section.name}}
</li>
<ul>
<li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu($index)" ng-repeat="tutorial in section.tutorials">
{{tutorial.name}}
</li>
</ul>
</ul>
here's a Plunker http://plnkr.co/edit/bJUhI9oGEQIql9tahIJN?p=preview
Each ng-repeat creates a child scope with the passed data, and also adds an additional $index variable in that scope.
So what you need to do is reach up to the parent scope, and use that $index.
See http://plnkr.co/edit/FvVhirpoOF8TYnIVygE6?p=preview
<li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu($parent.$index)" ng-repeat="tutorial in section.tutorials">
{{tutorial.name}}
</li>
Way more elegant solution than $parent.$index is using ng-init:
<ul ng-repeat="section in sections" ng-init="sectionIndex = $index">
<li class="section_title {{section.active}}" >
{{section.name}}
</li>
<ul>
<li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu(sectionIndex)" ng-repeat="tutorial in section.tutorials">
{{tutorial.name}}
</li>
</ul>
</ul>
Plunker: http://plnkr.co/edit/knwGEnOsAWLhLieKVItS?p=info
What about using this syntax (take a look in this plunker). I just discovered this and it's pretty awesome.
ng-repeat="(key,value) in data"
Example:
<div ng-repeat="(indexX,object) in data">
<div ng-repeat="(indexY,value) in object">
{{indexX}} - {{indexY}} - {{value}}
</div>
</div>
With this syntax you can give your own name to $index and differentiate the two indexes.
Just to help someone who get here... You should not use $parent.$index as it's not really safe. If you add an ng-if inside the loop, you get the $index messed!
Right way
<table>
<tr ng-repeat="row in rows track by $index" ng-init="rowIndex = $index">
<td ng-repeat="column in columns track by $index" ng-init="columnIndex = $index">
<b ng-if="rowIndex == columnIndex">[{{rowIndex}} - {{columnIndex}}]</b>
<small ng-if="rowIndex != columnIndex">[{{rowIndex}} - {{columnIndex}}]</small>
</td>
</tr>
</table>
Check: plnkr.co/52oIhLfeXXI9ZAynTuAJ
Just use ng-repeat="(sectionIndex, section) in sections"
and that will be useable on the next level ng-repeat down.
<ul ng-repeat="(sectionIndex, section) in sections">
<li class="section_title {{section.active}}" >
{{section.name}}
</li>
<ul>
<li ng-repeat="tutorial in section.tutorials">
{{tutorial.name}}, Your section index is {{sectionIndex}}
</li>
</ul>
</ul>
When you are dealing with objects, you want to ignore simple id's as much as convenient.
If you change the click line to this, I think you will be well on your way:
<li class="tutorial_title {{tutorial.active}}" ng-click="loadFromMenu(tutorial)" ng-repeat="tutorial in section.tutorials">
Also, I think you may need to change
class="tutorial_title {{tutorial.active}}"
to something like
ng-class="tutorial_title {{tutorial.active}}"
See http://docs.angularjs.org/misc/faq and look for ng-class.

Resources