'ng-repeat' re rendering creates a flicker - angularjs

I am using ng-repeat to list all the "zones". It works just fine on the first rendering and even when additional data from the server is added to the existing data it works without any issues or flickers. But when the "$rootScope.zones" is assigned a new value (the user can change the sort order from Alphabetical to Proximity, which sets a new value for the $rootScope.zones in that sorting order) the whole ng-repeat list goes blank for a few seconds and then works fine again.
This is not a very big issue except in the zones I have some text with CSS bubbles around. The text disappears but the bubbles remain.
How can I set the $rootScope.zones such that it doesn't create that flicker? Alternatively, how can I make sure that the "bubbles" only appear when the text is there.
This is my ng-repeat:
<ion-list class="card" ng-if="$root.currentMode.zoneBroadcast == true" can-swipe="true">
<div class="button-bar no-padding">
<button class="button bold" ng-class="{'button-calm': sortMethod === 'Alphabetically'}" ng-click="changeSortMethod('Alphabetically')">Alphabetically</button>
<button class="button bold" ng-class="{'button-calm': sortMethod === 'By Proximity'}" ng-click="changeSortMethod('By Proximity')">By Proximity</button>
</div>
<ion-item class="item no-border no-padding dark-bg" ng-repeat="zone in $root.zones track by zone.zoneName"
ng-if="checkVisibility(zone.zoneName)">
<div class="item-divider text-center">
<span>
Zone ID : <span>{{zone.zoneName}}</span>
</span>
</div>
<div class="item-body" ng-class="checkIfZoneMatches(zone.zoneName) ? 'zone-broadcast-green' : parseStringToInteger(zone.Trips.length) > 0 ? 'zone-broadcast-red' : checkIfZoneCanBookIn(zone.zoneName) ? 'zone-broadcast-yellow' : zone.Lineup.FreeList.length > 0 ? 'zone-broadcast-blue' : 'zone-broadcast-normal'">
<div class="row">
<div class="col">
<span ng-class="{'lineup free' : zone.Lineup.FreeList.length != 0}">{{zone.Lineup.FreeList.toString()}}</span>
<span ng-class="{'lineup loaded' : zone.Lineup.LoadedList.length != 0}">{{zone.Lineup.LoadedList.toString()}}</span>
<span ng-class="{'lineup accepted' : zone.Lineup.AcceptedList.length != 0}">{{zone.Lineup.AcceptedList.toString()}}</span>
<span ng-class="{'lineup offered' : zone.Lineup.OfferedList.length != 0}">{{zone.Lineup.OfferedList.toString()}}</span>
<span ng-class="{'lineup break' : zone.Lineup.BreakList.length != 0}">{{zone.Lineup.BreakList.toString()}}</span>
<span ng-class="{'lineup stc' : zone.Lineup.STCList.length != 0}">{{zone.Lineup.STCList.toString()}}</span>
</div>
</div> ...
I have tried ng-if, ng-hide, track by, etc. but nothing seems to work.
Here's the CSS I am using to create the bubbles.
.lineup{
background: white;
border-radius: 2em;
font-weight: bold;
font-size: 100%;
padding: 1%;
}
.free {
color: #00b140;
}
.loaded{
color: #6b46e5;
}
.accepted{
color: #0a9dc7;
}
.offered{
color: deeppink;
}
.break{
color: orangered;
}
.STC{
color: saddlebrown;
}
I expect the bubbles to appear only when the text is there. Moreover, when the sort order is changed by the user it should not go blank for over 2 seconds then render the template.
I would really appreciate your help.

Instead of using ng-if with ng-repeat, pipe to a filter:
SLOW
<ion-item class="item no-border no-padding dark-bg"
ng-repeat="zone in $root.zones track by zone.zoneName"
ng-if="checkVisibility(zone.zoneName)">
Faster
<ion-item class="item no-border no-padding dark-bg"
ng-repeat="zone in zones | filter : zoneFilter track by zone.zoneName">
$scope.zoneFilter = function(item) {
return $scope.checkVisibility(item);
};
For more information, see
AngularJS filter API Reference

Changing
zone.Lineup.FreeList.length != 0 to zone.Lineup.FreeList.length > 0 solved the bubble problem.

Related

Nested ng-repeat performance issue in IE

Am using nested ng-repeat to display below JSON ( given sample format actual format is different and have lot of properties ). When list size is 100 then in IE it takes more than 25 seconds to render.
I tried using "track by" & "oen way binding" but no luck.
Data
{name: "name1", placeVisited: [{city: 'city1', state: "state1"}]}
HTML
<div ng-repeat="item in items track by item.name" class="col-md-4 col-sm-6" style="float: none; display:inline-block; vertical-align: top; cursor: pointer" >
<a class="tile" id="tile{{$index}}" >
<div class="tile-head">
<div class="tile-ont-img"><img src="user.png" class="img-responsive" > </div>
<h4>{{::item.name}}</h4>
</div>
<div class="tile-body" >
<p ng-repeat="place in ::item.placeVisited track by port.state" >
State {{::place.state}}
</p>
</div>
</a>
</div>
Please share your idea to improve nested ng-repeat performance in IE.

How can i highlight a list card item on another view in ionic when navigating?

I have a list of unread "comments" in a menu - when i click i want to navigate to the comments group (a card item list), higlight and scroll to its $index.
I navigate to the group of cards like so:
ng-href="#/app/comments/{{comment.group}}#{{comment.id}}"
Using $stateparams I grab the group id comment.group and list all the comments listed like so:
<div class="list card fade" ng-repeat="comment in comments track by comment.id">
<div class="item item-avatar item-button-right item-stable">
<img ng-if="!userInfo.image" src="img/icon.png">
<img ng-if="userInfo.image" ng-src="{{userInfo.image}}">
<span ng-bind-html="userInfo.status"></span><span class="dark">{{userInfo.name}}</span>
<p class="date">{{comment.date | date:'M/dd/yy'}} {{comment.date | date:'h:mma'}}</p>
<button class="button button-clear" ng-if='canDelete' ng-click='deleteComment()'>
<i class="icon ion-ios-trash-outline"></i>
</button>
</div>
<div id="{{comment.id}}" class="item item-text-wrap item-button-right">
<span style="margin-left: 10px;">"{{comment.text}}"</span>
</div>
</div>
I set the id of the item text area to the comment.id
I'm trying to fade in all the cards and highlight comment.id item with the following css/scss:
.fade.ng-enter {
/* standard transition code */
transition: 1.0s linear all;
opacity:0;
}
.fade.ng-enter-stagger {
/* this will have a 100ms delay between each successive leave animation */
transition-delay: 0.4s;
transition-duration: 0s;
}
.fade.ng-enter.ng-enter-active {
/* standard transition styles */
opacity:1;
}
//Higlighting
:target{
-webkit-animation: target-fade 3s 1;
}
#-webkit-keyframes target-fade {
0% {
background-color: rgba(255,0,0,.1) !important;
}
100%{
background-color: rgba(0,0,0,0) !important;
}
}
both the fade and target-fade animations aren't working.
I do not know how to scroll to the index of the card in ionic - I was hoping the # tag would act as an anchor and work its magic...
can anyone help with this?

AngularJS - ng-repeat horizontally x number of times, then new line

I am trying to perform a simple ng-repeat on an <li>. In the past, i have created vertical ng-repeat. I am now trying to create a horizontal one, however, one that displays 4 items, then starts the ng-repeat again on a new line.
The way i have gone about this is using the grid-wrap technique (CSS) found here: http://builtbyboon.com/blog/proportional-grids
So each <li>, has a CSS class/width of one-quarter (25%).
Is this the correct/Angular way of going about it? Or should i be using some kind of $index on the <li> and triggering a <br> when $index == 3 ?
HTML:
<div ng-controller="MainCtrl">
<ul class="grid-wrap one-whole">
<li ng-repeat="product in Products" class="grid-col one-quarter">
<div class="product-container">
<div>{{ product.ModelNo }}</div>
<img ng-src="{{product.ImgURL}}" width="80%"/>
<div>${{ product.Price }}</div>
</div>
</li>
</ul>
</div>
CSS:
.grid-wrap {
margin-left: -3em;
/* the same as your gutter */
overflow: hidden;
clear: both;
}
.grid-col {
float: left;
padding-left: 3em;
/* this is your gutter between columns */
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.one-quarter {
width: 25%;
}
Here's my plunkr: http://plnkr.co/edit/REixcir0gL0HGCTvclYN?p=preview
Any other improvements you see feel free to add.
Thanks
I did some research and found this answer:
Customize ng-repeat in AngularJS for every nth element
<div class="section">
<div ng-repeat="items in MyList">
<img ng-click="AddPoint($index)" src={{items.image}} />
<span>{{items.currentPoint}}/{{items.endPoint}}</span>
<br ng-if="!(($index + 1) % 4)" />
</div>
So you could use this:
<br ng-if="!(($index + 1) % 4)" />
There doesn't seem to be a better way. You probably can't get around using index.

Ng-Repeat - Angular JS

Here is my ng-repeat
<div ng-if="feed.link" articlesource source='{{article.link}}' class="post" ng- repeat="article in data.value.items | limitTo:5">
<img ng-if="articlesource != 'FACEBOOK'" title="{{article.title}}" alt="{{article.title}}" class="blog-image-ind" src="{{article.image}}" height="100" width="240" style="float:left;">
<img ng-if="articlesource == 'FACEBOOK'" title="{{article.title}}" alt="{{article.title}}" class="blog-image-ind" src="/shared/images/facebook_long.png" height="100" width="240" style="float:left;">
<div class="postMid">
<H3><a style="color: #A4A4A4;" href="{{article.link}}">{{article.title | htmlToPlaintext | ellipsis:40}}</a></H3>
<div> {{article.description | htmlToPlaintext | blogellipsis:160}}</div>
</div>
<div class="postRight">
<p> {{article.pubDate.substr(0, article.pubDate.indexOf(':')-2).trim()}}
<br>
<div ng-if="feed.name != 'THE FEED'"><p ng-if="articlesource != 'FACEBOOK' || feed.name != 'THE FEED'">BY {{article['dc:creator'] | uppercase}}</p></div>
<p ng-if="feed.name == 'THE FEED'">{{articlesource}}</p>
</p>
<a ng-if="articlesource != 'FACEBOOK'" class="postRight" href="https://sam.containerandpackaging.com">{{article['slash:comments']}} Comments </a>
</div>
<br clear="all">
</div>
I would like to add something into my ng-repeat that would allow a border on all of the bottom of the divs except for the last one.
Use Css
div.post {
border-bottom: #ff0000;
}
div.post:last-child {
border-bottom: none;
}
The :last-child selector matches every element that is the last child of its parent.
Put a class on the repeater with the condition that $last isnt true:
ng-class="{'myBorderClass : !$last }"
$last is true on the last iteration of your repeater.
Ypu can use ng-repeat's $last value to set up ng-class. Something like pseudo code below.
<div ng-class="{'noborderclass':$last}"></div>
You have two options: Javascript (Angular), or CSS. With angular, you can use $last like so:
<div ng-class="{'with-border': !$last}">
With CSS, you can use the selector :last-of-type:
div {
border-bottom: 1px solid black;
}
div:last-of-type {
border-bottom: 0;
}
Personally, I go with CSS, cause I trust CSS more than JS.

Insert something between elements generated with ng-repeat

What would be the best way, to append an element in between elements generated using ng-repeat?
For example:
<div class="block" ng-repeat="position in [1,2,3,4,5,6,7,8,9,10]">{{position+1}}</div>
I would like to put a <br> after every 4th element. My guess would be to create a directive with the link.post. Tell me if I'm on the good track.
Thank you
jsFiddle: http://jsfiddle.net/uPMZU/
I'm not entirely sure what you're trying to achieve with the <br> but if your are trying to stack them in groups of four then you can do something using the $index variable from ng-repeat and a class change.
JSFiddle with this: http://jsfiddle.net/y44Cb/13/
HTML
<div ng-class="{block: ($index +1) % 4}" ng-repeat="position in [1,2,3,4,5,6,7,8,9,10]">
<div class="red-block">{{position+1}}</div>
</div>
CSS
div.red-block {
display: inline-block;
border: 1px solid red;
width: 50px;
height: 50px;
}
div.block {
float: left;
}
You could use ng-repeat-start and ng-repeat-end and then check whether you want to render the break in a function.
<div class="block" ng-repeat-start="position in [1,2,3,4,5,6,7,8,9,10]">
<div class="red-block">{{position+1}}</div>
</div>
with
<br ng-if="includeBreak(position)" ng-repeat-end>
or
<p ng-if="includeBreak(position)" ng-repeat-end></p>
You can use an ng-switch to do what you need
<div class="block" ng-repeat="position in [1,2,3,4,5,6,7,8,9,10]" data-ng-switch on="($index + 1) % 4 == 0 && $index > 0">
{{position+1}}
<br data-ng-switch-when="true">
</div>
jsfiddle: http://jsfiddle.net/7qrne/ if you inspect the "5" div you'll see it has the same with the "9" div, but none of the others.

Resources