Conditional render in ng-repeat - angularjs

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.

Related

Angularjs material one row with 2 columns

i am trying to achieve that, and can't figure how:
|-------------80%---------------------|----20%---|
one row with 2 columns with specific width.
i don't understand something, columns (usage in Material) are look to me like rows > in rows
|-------------------------------------|----//---|
|-------------------------------------|----//---|
|-------------------------------------|----//---|
and not like my example.
How can i achieve it?
After you have imported AngularJS and Angular Material (including the css file), you need to import Angular Material in your AngularJS app. To do this, you need to add the "ngMaterial" provider in your AngularJS module, like this:
var app = angular.module("myApp", ["ngMaterial"]);
(if you skip this part, it won't work).
Then you can write your HTML code as follows
<div layout="row" layout-wrap>
<div flex="80">80%</div>
<div flex="20">20%</div>
</div>
This will create a div that will act as a container. It will contain the elements you want to show and they will be aligned in a row and, if necessary, they will be displayed in a second row. In the flex property you can specify the width (as a percentage) of the element compared to the width of the container.
Obviously you can change the name of your Angular module and the number/ width of your html elements as you want.
And there you can see some examples and a bit of documentation
First you need to declare:
md-cols Number of columns in the grid.
In your case (8+2=10):
<md-grid-list md-cols="10" ...
Then your items:
<md-grid-tile md-colspan="8">...</md-grid-tile>
<md-grid-tile md-colspan="2">...</md-grid-tile>
Codepen Sample - Angular Material Docs

Performance issue in ionic framework

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

New bindings in already compiled page

I have a problem using the footable plugin with angular,
the problem is that footable appends new table rows to my table, but it pastes raw html text instead of angular replaced values, I mean {{'COMMENT'|translate}} instead of 'Comment' (see 'appended table image')
appended table image
I added click event, to perform special action to reevaluate, but I am not sure how to rebind the element HTML.
Table html
<th data-hide="phone,tablet" >{{'QUANTITY'| translate}}</th>
...
<tr ng-repeat="item in items | filter:itemsFilter" on-last-repeat ng-click="rowExpanded($event)" >
<td>{{item.Stock}}</td>
...
</tr>
Please let me now if you need more info. I'm quite stuck, tried googling, but i thing I don't know the term of my problem.
EDIT: It seems to me that footable caches table headers on init, and then reuses those values that are not compiled by angular yet, maybe that could help to find the answer.
Problem is that angular doesn't know that details row exist, and bindings inside it aren't replaced with values
expanded first row with console view
I figured out, that I need to recompile next element that is appended to the footable, I added ng-click on table rows:
<tr ng-repeat="item in items | filter:itemsFilter" on-last-repeat ng-click="rowExpanded($event)" >
Then in the controller, I found that currentTarget.nextElementSibling will return, next table row, which happens to be that uncompiled, new details row, so $compile does the trick. However this doesn't work when the row is already expanded and window being is resized, added columns in the details row will be in {{variablename}} syntax. But I guess I can live with that downside
$scope.rowExpanded = function($event){
$timeout(function(){
console.log($event.currentTarget.nextElementSibling);
$compile($event.currentTarget.nextElementSibling)($scope);
});
};
EDIT: Ok this didn't work when I used the <progressbar> template. Because at the time when footable reads data it is just a bunch of divs, and when i ask angular to compile those, it cant compile because bunch of divs isn't a >progressbar<
But yet, I found another solution, I delayed the footable initialization after everything is done on angular side:
TL;DR; I removed class 'footable' from table so it wont initialize automatically and call .footable() on the table element only after all of the ng-repeat rows were added (and compiled) to the table. This solves all my current footable/angular relation problems.
Try spacing out your translation statement, so instead of
{{'COMMENT'|translate}}
try
{{ 'COMMENT' | translate }}

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>

Stop AngularJS inserting <span class="ng-scope"></span> using ng-include

I'm using the Foundation layout framework, which automatically floats the last sibling of .column to the right and I really appreciate this is a behaviour. However, AngularJS takes it upon itself to insert span.ng-scope after every div.column, which somehow causes browsers to consider the last span the last sibling of .column (even though it is not).
Specifically the css in Foundation responsible for this is:
[class*="column"] + [class*="column"]:last-child { float: right; }
As I understand it, [attribute*="substring"] should select only siblings that match, so, for the above, only elements whose class attribute contains column (including columns). I would think a span tag whose class attribute that does not contain column should not match (and thus be ignored by :last-child). However, this does not seem to be the case.
Regardless, the span is causing the problem:
Angular buggering it up (jsfiddle)
Works fine without Angular (same jsfiddle, no ng-include)
Is there a way to configure angular to stop inserting those span tags? I would, begrudgingly, modify the css selector to somehow ignore all span tags; however I might eventually need/want to use a span tag.
Since you indicated the div can be moved inside, this works:
<ng-include src="'main.tmpl'"></ng-include>
Then in your template:
<div class="row">
<article id="sidepanels" class="four columns">
...
</div>
I'm not aware of any way to prevent angular from inserting the span tags (I think it keeps track of scopes that way -- for garbage collection).
Also you can try my version of include directive that does not creates a scope: Gist source.
As no scopes are created, AngularJS should not create additional element to mainain scope (it actually use data attributes to store link to scope).

Resources