Infinite number of slides appended to an angular-carousel - angularjs

I use rn-carousel with ng-repeat and I am able to swipe between all my items. However there is an infinite number of blank items appended to the list, meaning that I can swipe past my own items to the right an infinite number of time, it displays empty slides.
This happens even with a very basic markup:
<ul rn-carousel rn-carousel-controls class="swiper-container">
<li ng-repeat="p in UseCaseCtrl.getProjects()">
<img ng-src="{{p.picture}}">
</li>
</ul>
and regardless of the device.
Also the next '>' control link is never displayed on any slide, which is quite misleading when the user lands on the first slide and does not even know there are others slides on the right.
Any guess on what could be the source of the problem? Or a way to debug?

In case someone faces the same issue, the root cause was my implementation of UseCaseCtrl.getProjects() which used to return an object. Internally, rn-carousel will use .length to determine the number of slides. Since it tried to make .length of an object with nested items, it could not work. The problem was solved by returning an array instead.

Related

Angular not updating list fast enough

I have a list of 'cards' that when a filter is selected on the left side of the screen, the cards shown in the middle of the screen will update accordingly. Here is a snippet of the js:
$scope.isReady = false;
// This is an async method to retrieve from DB
AssignmentManagerService.getAssignmentsForClass(teacherId, classId).success(function(response) {
var instances = response.instances;
$scope.assignmentListData = instances;
$scope.isReady = true;
});
And here is a piece of the template:
<div flex class="item-list" ng-if="isReady">
<md-card ng-repeat="assign in assignmentListData track by assign.instanceId"
ng-click="selectCard(assign)"
class="item-list-item"
style="font-size:16px;"
ng-class="getCardClass(assign)"
ng-style="getCardStyle(assign)">
<div>
<span style='font-weight:500'>Title</span>: {{assign.title}}
</div>
<div style="margin-top:10px;">
<span style='font-weight:500' ng-if="assign.availableDate">Available Date:</span> {{assign.availableDate | date:'fullDate'}}
<span style='font-weight:500' ng-if="assign.createDate">Create Date:</span> {{assign.createDate | date:'fullDate'}}
</div>
</md-card>
</div>
One of two things will happen: I will either get two sections of cards on top of each other, one section with the old selection and one section with the new selection, for a half second before the old selection is removed OR the cards will all be integrated before the old cards are removed. All of this happens within the time span of a second but looks very unprofessional and ugly.
What is supposed to occur is the user makes a filter selection, the cards immediately hide, the new data is retrieved, and the new cards are shown. No overlapping, no multiple groups.
Here's what I have done:
Wrapped the async method/success into a $timeout function: Didn't work. Same results.
Wrapped the async method/success into a $scope.$$postDigest function: Didn't work. Same results.
Added a 400ms thread sleep in the back-end: While it does work, I'm not inserting a back-end fix for a front-end problem.
Tried various combinations of ng-if/ng-show on the div and the md-card: Didn't work. Same results.
The template was originally ~500 lines. I have stripped out all the extraneous markup except for this card bit to see if it was the digest cycle taking too long. Didn't work. Same results.
Any help would be greatly appreciated. Thanks!
Wow. My coworker and I just found some really old and buried CSS animations that were affecting the list in question. After removing them, everything works as it should. Doh! I'd like to thank #The.Bear and #JBNizet for pointing me in the right direction on this!

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>

Detecting page scroll/ current section being viewed in AngularJs

My page is divided into sections : #page-1 and #page-2
See Plnkr: http://plnkr.co/edit/RZJLmsWDfs63dC0QuDJi
<body>
<section id="page-1">
This is page 1. It takes the whole height of the browser. User has to scroll down to see page-2.
</section>
<section id="page-2">
<span class="animated bounce">This is page 2 </span>
</section>
</body>
Animation classes are being applied to different elements in #page-2.
However by the time the user scrolls down to these elements, the animation has already finished. Hence they just look like static objects.
Is there anyway I can detect when #page-2 is currently being viewed and then call a function to addClass('animated bounce') to certain elements ?
I would like to achieve this in angularjs if possible
I have found a angularjs directive that is probably helpfull for you in this case. Inview tries to solve this exact problem by reporting to you if a dom element is visible on the screen. Unfortunately I have been unable to test my solution because I couldn't find a minified js file of Inview but I assembled some code that should work:
<section id="page-2" in-view="{$inview ? isFocused=true;}">
<div ng-class="{'animated bounce': isFocused}">This is page 2 </div>
</section>
The $inview is supposed to be true whenever the element is in visible in the browser. This leads to the scope variable isFocused being set to true and therefor the animation class is added to your div.
This should work as you have intended in your question, if it does not work for some reason please let me know so I can improve my answer.

toggle skips/misses 2nd sidebar

Today's bogglement! I have two sidebars and a main content area. When I click on a button to expand the page, the sidebars should go away and the main content area spreads to 100%. (I'm trying to do something like what quandl.com does in its api displays, which is totally nifty.)
This should be really simple! I just add a class of 'apponly', which set the main-content to 100% and the sidebars to display:none. In my controller, I've got:
$scope.toggle = function() {
$scope.displayed = !$scope.displayed;
}
and in my html, I've got basically:
<div class="sidebar left" ng-class="{'apponly' : displayed }">
--something something--
</div>
<div class="main-content" ng-class="{'apponly' : displayed }">
<button class="btn btn-info device" ng-click="toggle()">[icon]</button>
--something something--
</div>
<div class="sidebar right" ng-class="{'apponly' : displayed }">
--something something--
</div>
...but it consistently only applies the class 'apponly' to the first sidebar and main content, and leaves the second sidebar intact (wrapped around to the next line, but still right there, w/no class of 'apponly' applied).
I tried to set up a plnk (http://plnkr.co/edit/ER4TPGexGnZ8knb4ThXQ?p=preview) but it won't work at all [okay that was a stupid oversight, now it does work except now I'm even more confused]. What really simple obvious thing am I totally missing here?
many thanks in advance!
AS PSL said, juste update your plunkr to <body ng-app="app" ng-controller="mainController"> and it will work. It actually does what you were expecting, so the issue is probably somewhere else.
Welp, I might as well answer since I (sort of) figured it out, and you never know, I might not be the only one baffled by such behavior.
It's tied to the animation. If you take the animation away, then everything behaves. You add it back in, and things get wacky again.
Why is this? I have no idea. But when I took the animation off the sidebars (so they simply disappear immediately), then the right-hand sidebar doesn't get pushed to the next line and end up remaining despite the added-class that should make it disappear. From behavior at least, it seems that the browser is trying to render animation at the same time the css-class is trying to make the section disappear. Which doesn't make any sense, b/c this works fine in other places, but all I know is that if you leave the animation on the main (middle) part, and turn it off on the sidebars, then everything behaves properly.
I'm not counting this as an answer, though, since it's more of a "well, that fixed it, if inadequately," which is less of an answer and more of a workaround left here for posterity, the enlightenment of any confused devs behind me, and the entertainment of any senior devs wandering through.

How do I prepend a new item to an ng-repeat list?

I have situations where I need to prepend an item to a list that is initially generated using ng-repeat. How do I do this?
<div ng-click="prependItem()>Click Here</div>
<div ng-repeat="item in items">
<div class="someClass">Item name: {{item.name}}</div>
<div class="anotherClass">Item type: {{item.type}}</div>
</div>
If I click on prependItem() I want want the new item to be added to the top of the list. Obviously, I don't want to regenerate the entire ng-repeat. I've been unable to find any documentation that would explain how to do this. Thank ahead of time for any help!
scope.prependItem = function (newItem) {
items.unshift(newItem);
};
AngularJS is smart enough to know the addition, and only create html element for it
http://plnkr.co/edit/qzIfzSP6buiQ49rDreNk?p=preview
You can see from console that only the newly added item will log messages
ng-repeat will rebuild the list if you add an item to the front of your array. If you add it to the end it's smarter in that it will only update the DOM to reflect the change for the one item you've added in.
Because you've added an item to the front, it has to move everything in the DOM so I think it just rebuilds it as it's easier to do than moving (don't quote me on that though lol). It isn't necessarily a bad thing to rebuild that list (unless it's huge, you won't even notice the refresh, if it is very big, I'd recommend showing a spinner whilst it rebuilds the html, that's the approach we've taken at work; since the user has clicked the button they're expecting the interaction so the spinner seemed like the best compromise whilst angular rerendered).

Resources