AngularJS performance issue ng-model vs ng-class etc - angularjs

I have a list with ng-repeat in angular and a button which toggle checked property in all items (1.4):
<button ng-click="selectAll()">select all</button>
example 1:
<li ng-repeat="item in items">
<input type="checkbox" ng-model="item.checked"> {{ item.name }}
</li>
example 2:
<li ng-repeat="item in items">
<span class="glyphicon" ng-class="{'glyphicon-ok': item.checked}"></span> {{ item.name }}
</li>
example 3:
<li ng-repeat="item in items">
<span class="glyphicon glyphicon-ok" ng-show="item.checked"></span> {{ item.name }}
</li>
example 4:
<li ng-repeat="item in items">
<span>{{ item.checked }}</span> {{ item.name }}
</li>
Performance of example 1 and 4 is OK. But example 2 and 3 has almost 1 sec. lag. There about 200 items in the array.
Why the performance is so different? I would like to have custom "checkboxes" with glyphicon - so I would like to have example 2 work but the performance is bad

You can try the following for example 2:
<li ng-repeat="item in items track by item.checked">
<span class="glyphicon" ng-class="{'glyphicon-ok': item.checked}"></span>
{{ item.name }}
</li>
For example 3, try this:
<li ng-repeat="item in items track by item.checked">
<span class="glyphicon glyphicon-ok" ng-if="item.checked"></span> {{ item.name }}
</li>

Related

Why does $parent.$index equals $index?

In AngularJS 1.6.3 it is basically possible to nest ng-repeat.
I have determined, that in two nested ng-repeat the $parent.$index equals $index.
The following code is given:
<div ng-repeat="category in :: $ctrl.categories">
<span id="category-{{ $index }}">
{{ :: category.name }}
</span>
<ul>
<li ng-repeat="data in :: category.links"
id="link-{{ $parent.$index }}-{{ $index }}">
{{ :: data.name }}
</li>
</ul>
</div>
Expected resulting ID's for LI:
<div>
<span id="category-0">CatA</span>
<ul>
<li id="link-0-0">[..]</li>
<li id="link-0-1">[..]</li>
<li id="link-0-2">[..]</li>
</ul>
</div>
<div>
<span id="category-1">CatB</span>
<ul>
<li id="link-1-0">[..]</li>
<li id="link-1-1">[..]</li>
</ul>
</div>
Actual resulting ID's for LI:
<div>
<span id="category-0">CatA</span>
<ul>
<li id="link-0-0">[..]</li>
<li id="link-1-1">[..]</li>
<li id="link-2-2">[..]</li>
</ul>
</div>
<div>
<span id="category-1">CatB</span>
<ul>
<li id="link-0-0">[..]</li>
<li id="link-1-1">[..]</li>
</ul>
</div>
Can someone confirm this behaviour? Or did I miss something?
Working as expected.
angular.module('test', []).controller('Test', Test);
function Test($scope) {
var $ctrl = this;
$ctrl.categories = [
{
name: 'cat1',
links: [{name: 'l1'}, {name: 'l2'}, {name: 'l3'}]
},
{
name: 'cat2',
links: [{name: 'l4'}, {name: 'l5'}]
}
]
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.3/angular.min.js"></script>
<div ng-app='test' ng-controller='Test as $ctrl'>
<div ng-repeat="category in :: $ctrl.categories">
<span id="category-{{ $index }}">
{{ :: category.name }}
</span>
<ul>
<li ng-repeat="data in :: category.links"
id="link-{{ $parent.$index }}-{{ $index }}">
{{ :: data.name }}
</li>
</ul>
</div>
</div>
You probably have some scope generating elements surrounding your child layer e.g. ng-if, ng-repeat, ng-switch. In this case you'll need to add more layers of $parent

how to select a li which is nested within another ng-repeat in angular js

(please do not update the english grammer in this question/ I wont be able to approve it and this question wont get resolved.)
This is my UI
It contains various li elements whose values are populated using this angular html
<div class="row">
<li class="no-bullet-li li-12 monaco-font"> {{selectedChangeEligibilityPlan}}</li>
<ul class="ul-plan-1">
<li class="no-bullet-li" ng-repeat="plan in fewThings">
<div ng-class="{ 'selected-class-name': $index == selectedIndex }" ng-click="itemClicked($index)" class="li-alt monaco-font"> p2|{{plan.planName}} | {{plan.planId}}
<a class="iconing-sub" ng-click="addClick(item)" href=""><i class="glyphicon glyphicon-plus"></i></a>
<a ng-click="deleteClick(item)" ng-class="{ active : active.one }" href=""><i class="glyphicon glyphicon-remove iconing_1-sub"></i></a>
</div>
<ul class="ul-plan">
<li class="no-bullet-li li-8 monaco" ng-repeat="item in plan.planIds">
p1| {{ plan.planNames[$index]}} | {{item}}
<a <a ng-click="editClick(item)" href=""><i class="glyphicon glyphicon-pencil iconing"></i></a>
<a ng-click="deleteClick(item)" href=""><i class="glyphicon glyphicon-remove iconing_1"></i></a>
</li>
</ul>
</li>
</ul>
</div>
It uses the nested ng-repeat.
The whole UI is contained within a one controller ( no directives used)
the following code gets triggered when someone clicks the blue lis.
$scope.itemClicked = function ($index) {
console.log($index);
// console.log($(item).closest('li') );
$scope.selectedIndex = $index;
};
here's how to ui looks and its great.
problem arises when I try to do the same logic for the pink ones (nested ng-repeat li). It selects other pink lis in all the other stack too.
here's the screenshot.
second part of question:
I have I have the above UI plus I also have this second UI that is loaded along with this on the same page. It contains a bunch of horizontal rows.
Once the user click the blue pink colored lis it goes into the active state. Then the user can click the row which he likes. upon clicking it the plan name of currently selected li will get replaced.
Here is the html for it.
<div class="row">
<li class="no-bullet-li li-12 monaco-font"> {{selectedChangeEligibilityPlan}}</li>
<ul class="ul-plan-1">
<li class="no-bullet-li" ng-repeat="plan in fewThings">
<div class="li-alt monaco-font"> p2|{{plan.planName}} | {{plan.planId}}
<a class="iconing-sub" ng-click="addClick(item)" href=""><i class="glyphicon glyphicon-plus"></i></a>
<a ng-click="deleteClick(item)" ng-class="{ active : active.one }" href=""><i class="glyphicon glyphicon-remove iconing_1-sub"></i></a>
</div>
<ul class="ul-plan">
<li ng-class="{ 'selected-class-name': $index == selectedIndex }" ng-click="itemClicked($index)" class="no-bullet-li li-8 monaco" ng-repeat="item in plan.planIds">
p1| {{ plan.planNames[$index]}} | {{item}}
<a ng-click="editClick(item)" href=""><i class="glyphicon glyphicon-pencil iconing"></i></a>
<a ng-click="deleteClick(item)" href=""><i class="glyphicon glyphicon-remove iconing_1"></i></a>
</li>
</ul>
</li>
</ul>
</div>
The problem lies in the fact that you are trying to save the state of the data (which one is selected) inside your controller using $index. The $index property isn't unique among different ng-repeats, so when you set your $scope.selectedIndex to $index, each of your sub lists will see that their $index matches, and so will each trigger the ng-class and add the selected-class-name class.
What you could do instead is have each item in the data have a unique index and use that id to store which item is selected in $scope.selectedIndex.
<ul class="ul-plan">
<li ng-class="{ 'selected-class-name': item.id == selectedIndex }" ng-click="itemClicked(item.id)" class="no-bullet-li li-8 monaco" ng-repeat="item in plan.planIds">
p1| {{ plan.planNames[$index]}} | {{item}}
<a ng-click="editClick(item)" href=""><i class="glyphicon glyphicon-pencil iconing"></i></a>
<a ng-click="deleteClick(item)" href=""><i class="glyphicon glyphicon-remove iconing_1"></i></a>
</li>
</ul>
This line looks strange.
<a ng-click="select('one')" href="">
Did you really mean to pass a hardcoded 'one' to the function? Or was it supposed to be the index, like the deleteClick() call.

How to loop only internal html/dom/content using ng-repeat?

I want to loop li with different condition and apply different html depending on that condition.
If i code this way
<ul ng-repeat="item in items">
<li ng-if="item == '1'">
<div><span> <span>My test 123</span>
{{item }}
</span></div>
</li>
<li ng-if="item == '2'">
<div><span class="xyz"> <span class="abc">My new test XXX</span>
{{item }}
</span>
<span>123</span>
</div>
</li>
</ul>
It repeat as
<ul ng-repeat="item in items">
<li>My test 123
1</li>
</ul>
<ul ng-repeat="item in items">
<li>
My new test XXX
2 123</li>
</ul>
But i want
<ul ng-repeat="item in items">
<li>My test 123
1</li>
<li>
My new test XXX
2 123</li>
</ul>
Any solution?
Thanks.
Repeat on the DOM element you want repeated?
<ul>
<li ng-repeat="item in items">{{item }}</li>
</ul>
<ul >
<li ng-repeat="item in items">{{item }}</li>
</ul>

Angular ng-repeat element count

<li ng-repeat="Item in Items">
<div ng-switch="($index)==0">
<div ng-switch-when="true">
< Previous
</div>
<div ng-switch-when="false">
{{$index}}
</div>
</div>
</li>
I want to get element count of the Items and want to show "Next >" for last item
Something like this
<li ng-repeat="Item in Items">
<a ng-if="$first" href="#">< Previous</a>
<a ng-if="!$first && !$last" href="#">{{$index}}</a>
<a ng-if="$last" href="#">Next ></a>
</li>
To get the length use Items.length. It becomes more complex if there is a filter. See this SO post

ng-hide depending on value of var

In AngularJS, how can I do what the following code is trying to achieve, i.e. hide a span if task.status is set to a specific value?
<li ng-repeat="task in tasks">
Move to:
<span ng-hide="task.status=todo">Todo</span>
<span ng-hide="task.status=doing">Doing</span>
<span ng-hide="task.status=done">Done</span>
</li>
<li ng-repeat="task in tasks">
Move to:
<span ng-hide="task.status == todo">Todo</span>
<span ng-hide="task.status == doing">Doing</span>
<span ng-hide="task.status == done">Done</span>
</li>
or
<li ng-repeat="task in tasks">
<div ng-switch on="task.status" >
<span ng-switch-when="todo">Todo</div>
<span ng-switch-when="doing">Doing</div>
<span ng-switch-when="done">Done</div>
</div>
</li>

Resources