Performance issue in ionic framework - angularjs

I have created the table with 50 rows and gave the css overflow is scroll to parent element of table. Each time of scrolling I will add 5 row in the table. It’s working fine in html. But I converted this to ionic framework, I got performance lag. Can any one suggest, why performance issue is occurring when perform DOM operation in ionic framework?

Remember to use the one-time-binding operator '::' in every angular directive that should execute or evaluate only once, I mean if you don't need to be watching for changes (ng-click, ng-class, ng-if, ng-switch...) and also in labels, texts, fields and stuff filled with your data.
Doing a ng-repeat with too much angular interaction can create a lot of watchers. Hence, the perfomance of your app will decrease dramatically. Imagine an ng-repeat of a portion of html with 1 ng-click, 1 ng-class and three fields. These are 5 watchers, so 5 X 50 rows are 250 watchers...
Also if your list is not going to change you can use algo :: on the ng-repeat directive. Example:
<div ng-repeat="item in ::ctrl.items"></div>

Instead of ng-repeat="item in items", for ionic you can use collection-repeat="item in items. It is a really optimized version of ng-repeat for ionic. For more info checkout this link: collection-repeat in ionic

Related

Why is my angular grid so slow?

So, I have made some custom directive which draws kind of a data-grid, based on floated divs (because nested flex implementation in FF sucks - but it's not the point).
How it works :
I pass some data collection to the directive via something like <the-grid data-list="parentController.displayedRows">
Inside this first directive, I have columns via something like <a-grid-column data-value="row.value"></a-grid-column> with many attributes I won't precise here.
The data-value value can be a direct expression, bound to the row on which the the-grid directive controller is ng-repeating in order to display each columns, or a function which have to be $eval-uated in order to display the intended value from the parentController.
In my <the-grid> directive controller, I have the rendering template of my grid which make a nested ng-repeat div (first one on the rows of the data-collection, second one on the columns, created in the directive), it looks like :
<div data-ng-repeat="row in list">
<div data-ng-repeat="cell in theGridColumns"
data-ng-bind-html="renderCell(row, cell)">
</div>
</div>
I have some keyboard nav in order to quickly select a row or navigate within pagination or many tabs, which does nothing more than applying some class on the selected row, in addition to update some "selectedRowIndex".
I'm using angular-vs-repeat in order to have the minimum of row divs in my DOM (because the app is running on slow computers). This works well.
The problem is that every time I'm hitting some "up" or "down" key on my keyboard, Angular is "redrawing" EVERY cells of the list.
So, let's suppose I've 200 rows in my data list, and 7 columns for each rows. First load of the page, it passes ~3000 times in the renderCell() function. Ok , let's accept that (don't really understand why, but ok).
I hit the down key in order to go to the second line of my list. It passes ~1100 times in the renderCell() function.
So yes, the result is very slow (imagine if I let the down arrow key pressed in order to quick navigate within my rows)... I can't accept that. If someone could explain that to me... Any help would be greatly accepted :)
If I make the same thing without a directive (direct DOM manipulation, with columns made by hand and not in a ng-repeat within a ng-repeat), every thing is smooth and clean.
Yes, I've look into every angular grid on the market. No one is satisfying me for my purpose, that's why I've decided to create my own one.
And no, I really can't give you some JSFiddle or anything for the moment. The whole app is really tentacular, isolating this is some kind of complicated).
Try to use bind once (angular 1.3+)
<div data-ng-repeat="row in ::list">
<div data-ng-repeat="cell in ::theGridColumns"
data-ng-bind-html="::(renderCell(row, cell))">
</div>
</div>

How to optimize ng-switch

I'm using angular's ng-switch to build form's fields like this
<div ng-switch="vm.myField">
<my-input-type1 ng-switch-when="type1"></my-input-type1>
<my-input-type2 ng-switch-when="type2"></my-input-type2>
<my-input-type3 ng-switch-when="type3"></my-input-type3>
<my-input-type4 ng-switch-when="type4"></my-input-type4>
<my-input-type5 ng-switch-when="type5"></my-input-type5>
<my-input-type6 ng-switch-when="type6"></my-input-type6>
<my-input-type7 ng-switch-when="type7"></my-input-type7>
<my-input-type8 ng-switch-when="type8"></my-input-type8>
</div>
because of performance it's not good solution (on entering view with it brwser is pausing for a while).
Without ng-switch all is rather ok.
How can I optimize it? ng-if has the same prefomrance issue.
As you probably know from the Angular documentation (https://docs.angularjs.org/api/ng/directive/ngSwitch)
ng-switch works by adding and removing the nested DOM element based on a conditional statement. This can be quite slow for large templates/DOM elements.
One solution I used was to use ng-show/ng-hide (https://docs.angularjs.org/api/ng/directive/ngShow).
These directives do not modify the DOM structure, but instead use CSS to hide/show the elements. It can be faster, but beware that the DOM could become very large if you fall into the trap of trying to contain all of templates/DOM elements of your web site in memory at the same time in this manner.
I think I found a solution.
Insead of ng-switch I'm using
<ng-include src="'/my-fields/directives/'+vm.myField+'.html'"></ng-include> with proper html code.
For now works good but have to test a bit more.
EDIT: now it is much, much faster

Conditional render in ng-repeat

I have an Angular webApp running with Bootstrap's css.
What I'm doing now is render a table based on some data stored in a matrix, but in some cases, some rows have not relevant data to show so what I do is hide those irrelevant rows. Problem comes here: bootstrap table that I'm using adds a grey background in the pair rows and white in the odd rows.
the code in the angular template that I use is the following:
<tr ng-repeat="row in estadisticasT1" ng-hide="row.Noches == 0 && estadisticasT2[$index].Noches == 0">
<directive ng-if="comparar && ((row.Noches - estadisticasT2[$index].Noches) >= 0)" class="comparativa2">+{{row.Noches - estadisticasT2[$index].Noches}}</directive>
<directive ng-if="comparar && ((row.Noches - estadisticasT2[$index].Noches) < 0)" class="comparativa3">{{row.Noches - estadisticasT2[$index].Noches}}</directive>
</tr>
I reduced the code to show only the relevant part, tags are useles for this example, the only interesting part is that I use a ng-hide with a comparsion in order to hide the irrelevant rows of my matrix, but the problem is that in some cases it renders like this:
As you can see the first two rows have a grey background and the next two have a white background. What I need to do is to show a grey background in the odd rows and white in the pair ones, but I can´t do this using the $index variable because it doesn't corresponds to the shown rows but all the rows being shown or not.
Any angular expert have an idea that could help me here ?
Thanks in advance
Instead of ng-hide, use ng-if. The latter removes the nodes entirely from the DOM tree, and as such, it shouldn't interfere with your parity-based CSS rules. See the details of the differences between nghide, ngshow and ng-if for example here, or in the angular docs themselves.

Angularjs : Display accolades {{ }} several milliseconds before rendering

I am going to create an application with Angularjs. I have several modals (with the ng-dialog libraries) to create, modify data like an user for example.
When I open it, I can always see during several milliseconds names variables with accolades like {{user.name}}, before it renders the real value.
It is not really beautiful and then if someone has an idea about how to manage this type of display problems, please share it.
Thank you in advance.
There are couple of ways to deal with it, you could either use ng-bind or ng-cloak directives
Check angular ngCloak directive documentation
https://docs.angularjs.org/api/ng/directive/ngCloak
You can use ng-bind. Here is the official documentation on it:
It is preferable to use ngBind instead of {{ expression }} if a template is momentarily displayed >by the browser in its raw state before Angular compiles it. Since ngBind is an element attribute, >it makes the bindings invisible to the user while the page is loading
Usage:
Hello <span ng-bind="name"></span>!

AngularJS using ng-if vs ng-show

In my AngularJS I have the following code where I check if there is a currently logged in user or not in order to switch the top app menu text from Login to Logout (login if no user is logged in) and vice versa. When I used ng-show ng-hide the app started to be extremely heavy so I tried switching to ng-if, but then the css effects on the top menu started not to work specifically in the login/ logout tab. So can someone please tell me what is the best approach to handle this situation with example please? Thanks
index.html
<div ng-controller="MenuController">
<li>
<div ng-if="userLevel() == 1">
Login
</div>
<div ng-if="userLevel() == 2">
Logout
</div>
</li>
</ul>
</div>
Controller:
controller('MenuController',
function MenuController($scope, UService){
$scope.userLevel = function(){
var userType = UService.checkULevel(); //This will return either 1, 2,3,4...etc
return userType;
};
});
The difference between ng-show and ng-if is that ng-show applies a display: none to the element when the specified expression is a false value, while the ng-if removes the node from the DOM, basically equivalent to the .empty in jQuery.
An approach you can consider for your element, is rather than using it within a controller, use a directive for the access level, and follow the approach described in this article, which is really flexible and allows you to have different elements in the UI depending on the user level: http://frederiknakstad.com/2013/01/21/authentication-in-single-page-applications-with-angular-js/
Another reason for your application to be slow when you check the user level, could be that every time that is evaluated your application has to perform a check on the server side, slowing the application. An approach for it would be to cache the result of that query, and then use it while the login status doesnt change. At that stage you can invalidate the cache and fetch the user level again, ready to update the UI.
The ng-if directive removes the content from the page and ng-show/ng-hide uses the CSS display property to hide content.
I am pretty sure that no-show is lighter than ng-if and no-show should not make the app too heavy. If it is becoming heavy, I think there could be other causes for it.
If you use ng-if the node is rendered only when the condition is true
In case of ng-show ng-hide the Nodes will be rendered but shown/hidden based on the condition if condition changes the same nodes are shown/hidden
when ever you use ng-if it will render only that code which satisfy the condition.
while ng-show ng-hide will render the code on page but will be hidden with the help of CSS properties.
so better to use ng-if for reducing the line of code to be rendered on page.

Resources