Nested Views in Angular UI-Router Lag During State Change - javascript

I have a parent view with a nested view in the middle.
On a state change, the nested view seems to stick for a second or two before loading the next state. It's as though the nested view is lagging behind or something.
For example, after logging in, the login form is still visible for a second or two in the middle of the page after the state change. The parent view changes instantly, but that nested view just seems to stick.
I've been pretty careful about items on the watch list, and use one-time binding wherever possible.
But I really don't think it has to do with that, because this happens even early on in the application (from login to the main page), and other than this issue, application performance is fine.
I've googled a lot about this, but haven't turned up anything useful.
Any ideas on what to check or how to debug this?

You say it only happens the first time you transition after loading the app. So it could be you are injecting a service into the child view that you are using the first time in your app. This service is taking some time to instanciante. Servises are singletons, so this lag is only visible the first time.
Look at the answer in this thread for a possible solution, somebody had the exact some problem:
How to instantiate a service dynamically?.
Another solution might me to inject that service into the parent view as well, so you get the lag while loading the app not on first transition.

Related

AngularJS Routing: Keep view loaded, but invisible (save scroll location and prevent reload of data)

So I'm trying to make a single page web application that makes use of AngularJS's routing mechanism and so far it's working brilliantly, but I noticed that when the route changes, the view seems to be completely deleted and replaced with the new one.
Is there any way to keep the old view around so that it doesn't have to re-download all of its data when the user goes back to it? Also it would be nice so that their scroll position would be retained.
Any ideas?
Using UI-Router I solved this problem with the angular ui router extras. Here you will find the sticky states that will perhaps do what you want. Quote from the website:
Sticky States allows a tree of states to be long-lived, running
concurrently alongside one or more other state trees. This is also
sometimes referred to as Parallel States. The basis for this
functionality is to implement a "tabs" use case. Using UI-Router
Extras Sticky States, a single page angular app can implement
independent tab state trees, which operate in parallel to each other.
Does that help?

Best practice to cache a Marionette View

In the application we are developing, we have a CollectionView whose every ItemView contains a link to the item-details page. Also, every ItemView contains a checkbox, because items can be selected in the CollectionView to perform bulk actions on them.
When switching to the ItemDetails view, we want to keep the state of the CollectionView, ideally without having to redraw it (a bit like GMail when switching from inbox to mail and back). Our solution is to render the two views in two different regions and to hide one when switching from one to the other.
My perplexity about this solution is that
Marionette doesn't seem to be meant for this kind of use.
It is not very memory-friendly, since all the DOM elements are never deleted.
Is there any better solution to achieve this goal?
Storing the state somewhere, close the CollectionView and redraw it later is another possible solution, but would it imply a heavy computation overhead? (we are quite scared about redrawing views).
Marionette allows for showing a view in a region without closing the view that was already rendered. You simply pass in {preventClose: true} to the show() method of the region. You would still need to maintain a reference to the collection view though so you can later re-show it or close it yourself.
https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.region.md#showing-a-view
Unless your collection is very large, there's not a problem with just rerendering the collectionView when switching back from a itemDetail view. You do need to store the state of the checkboxes indeed.
However, I don't see what's really wrong with your other approach. It's probably even faster and there's nothing wrong with just hiding one region and showing another. If that works for you, go ahead.
Regarding the memory issue, as long as you're looking at the collection or itemDetail there isn't much to gain by closing either one of the views (especially if your itemDetail views are not very large). Once you move away from that section (thus not looking at the collection or itemDetail view anymore) you could just close the layout that contains these two regions. That'll free up any memory used by these regions.

Angular-ui Router get two states active in parallel

I need to use two states in parallel, one for my page and an other for a modal with several sub states.
Right now calling the modal state will wipe out my page since the page state changed.
Create a child state child of my page wouldn't be a solution since the modal will be used on several pages.
Example:
$stateProvider
.state('user', {}) // page
.state('bookshelf', {}) // page
.state('books', {}) // modal
.state('books.read', {}) // sub state of modal
So if I'm on user and open my modal then the state would change to books, my modal would then have the content but the page content will be wiped out.
How do I fix it?
I believe the way you're looking to do this is not possible with UI.Router currently. What you're describing is a modal component (which would ideally be written as a directive), which tracks it's state independently from the main state.
The way to think about it, is that UI.Router works by creating a state tree. At any given time you can only be looking at one branch of the tree. You can go deeper down a branch (ie: book, book.open, book.open.checked), but you can't be in two places at once.
Another issue with the problem above is how do you serialize the state of the two different trees into one url? It's not to say it can't be done, it's just a hard problem to solve.
Checkout these issues:
https://github.com/angular-ui/ui-router/issues/119
https://github.com/angular-ui/ui-router/issues/384
https://github.com/angular-ui/ui-router/issues/475
Also checkout these repos, they might be further along the lines of solving the problem.
https://github.com/afterglowtech/angular-detour
https://github.com/stu-salsbury/angular-couch-potato
As far as solving your immediate problem, I think the 'easiest' way would be to ditch controlling the state of the modal inside your state config.
Instead, I would add some sort of root or abstract state, and then track whether the modal is open there. Then, you can communicate between controllers using events as shown here. Note: There are performance implications with listening to $rootScope, so be sure to research those. However (someone feel free to correct me), the implementation here doesn't have those problems, because the AppCtrl is never destroyed.
Jan 15, 2015 Edit
Turns out this is a pretty popular use case, and one of the core contributors to UI Router maintains a plugin/addition called UI Router Extras
It also includes utilities for lazy loading, called "Future States" which are very helpful.
That being said, one feature I'm hoping to get time to work on is maintaining all state within the URL (or perhaps, local storage) and allowing for reusable state "components". The latter is in the UI Router roadmap as well.

How to handle memory leak when using angular.js ngRepeat and Routes?

Angular is leaking DOM elements when I'm using ngRepeat with the Route service.
Our app has a table with search results. When the user clicks the next button on the pagination control, the app changes the route. So http://website/results/1 will become http://website/results/2 this causes angular to call compile on the ngRepeat directive which clears it's cache. The DOM elements and $scope objects in the cache are sticking around and leaking.
You can see this same issue on http://docs.angularjs.org/api/
Navigate to the site above, open dev tools and start the timeline. Then start clicking on the navigation on the left hand side. Start at the top and keep clicking until you get to the bottom of the nav then go back up.
You will see the DOM Node count just keep growing and never gets fully garbaged collected.
This is a real issue.
My question is: does anybody now how to fix this? Is there a work around?
Also, as a side note but still related is that angular appears to leak each element that is wrapping an inline expression. {{objectOnTheScope}}
It might be related to nested ng-repeat memory leak.
See https://github.com/angular/angular.js/issues/1313#issuecomment-10378451

Backbone.js: view states and routes

I'm thinking about the optimal way to structure my Backbone application. The problem is that I have various complex states, each made by some views showing while all the others are hidden.
What is the canonical way to handle this in Backbone? Two things that I've thought are either controlling the state by the router (calling views hide / show methods) or making the views listen for route event.
The problem with the first method is that the router must be aware of all the views existing in the application.
The problem with this second solution is that I have to make all the views listen to all the events and hide for any of them but a couple that make them show.
Thanks for pointing me to a lean solution.
I use a FSM machine to change the state of the application. Each states shows and hides the appropriate view. My views use transition to animate in and out, so changing the state is more complex, then simple show/hide - it animates in and out from one state into another. I have forked https://github.com/fschaefer/Stately.js to fit my needs.
I can share my personal experience with such a problem. I don't know if it's the best solution, but it worked for me.
My problem was even worse because I had several routers and each of them should hide/show views that belong to it. The solution I chose was similar to the first option you consider.
In my router there is an array which holds all existing views. When the state changes and route callback executes all other views are hidden with this simple code view[i].hide() and the proper one is shown. You can make View model and Views collection if you would like to have more control.
I think it's a better solution, because when you add a new route, you don't have to add route events to all views. Moreover, your views stay decoupled from the router, they may even don't know it exists.

Categories