Router 2.0 fails to render views when cacheViews is not defined #276

Closed
rwhepburn opened this Issue Aug 26, 2013 · 26 comments

Projects

None yet

8 participants

@rwhepburn

I have run into a big issue where if the cacheViews setting is not enabled for the router binding handler and you trigger multiple views very quickly it appears to break the app. Luckily I was able to repro this with the Durandal samples by doing the following:

  1. Edit ko\index.html and remove the cacheViews setting as follows: <!--ko router: { transition:'entrance' }--><!--/ko-->
  2. Run the sample app.
  3. Click the 'Knockout Sample' menu item to load the Knockout samples.
  4. In the left navigation bar, rapidly click between the Hello World sample link and the Click Counter sample link.

If you do Step 4 fast enough, the router binding handler will eventually fail to render the content. After this happens clicking any links in the nav menu will no longer render any modules into the content area until the browser is refreshed.

@EisenbergEffect
Blue Spire member

Does it happen if you remove the transition as well?

@rwhepburn

Nope, I can't repro if I remove the transition. Certainly seems like it's related to the transition.

@EisenbergEffect
Blue Spire member
@EisenbergEffect
Blue Spire member

Also, I accepted your TS patch. So, if you happen to find the bug and want to submit a patch, I'll gladly accept it, provided that it doesn't break any other existing behavior ;)

@rwhepburn
@rwhepburn

I had a little time today to look at this. It seems this is related to the Router plug-in not properly tracking state on the isProcessing() observable in certain navigation scenarios.

Once you get the system into this known bad state (by following the steps above and rapidly switching between views) the isProcessing() observable in router.js stays set to true. Afterwards, any time you click a link in the nav menu the invoked route seems to just get queued and is never de-queued. This is because the dequeueInstruction() method checks the isProcessing() observable and always returns if it's true. This means it will never processes the next instruction. I think this is what makes it seem like nothing is happening in the UI. What's actually happening is the route is getting queued but just never gets processed. If I debug the code and manually do a reset isProcessing(false), navigation starts working again.

This is likely caused by a timing issue that occurs when a new route is invoked before a previous active route has finished navigating.

At this point, my head is spinning trying to figure out how to fix this.

@EisenbergEffect
Blue Spire member

Can you perform a quick experiment? If you move isProcessing(false); into router.compositionComplete, does that fix the issue?

@EisenbergEffect
Blue Spire member

Actually, you will also need to move the call to dequeueInstruction as well, after you set isProcessing(false);. See if that makes any difference.

@rwhepburn

Unfortunately didn't make a difference. What I can tell is that when the router is in the bad state, the binder's doBind(...) function never gets called to bind the requested view and view model together. I guess that's why they never get composed and injected into the DOM.

@rwhepburn

Not sure if this helps, but I also can only reproduce this when navigating between child routes.

@EisenbergEffect
Blue Spire member

This may also be l inked to the issue around transitions and route breaking.

@hikalkan

I have the same problem. It occurs when using transition: enterance and not caching views.

@zsmorris

+1. I've got the same problem. Could the router apply something like 'transitioning-in' and 'transitioning-out' classes in addition to the current transition mechanism? That way we could use CSS transforms/transitions/animations instead of relying on transition plugins.

@EisenbergEffect
Blue Spire member
@zsmorris

Done. Thanks for such great work!

@zabolots

Is this related to the issue referenced in the answer by marvc1 at http://stackoverflow.com/questions/18402706/hottowel-converting-to-durandal-2-issue

I'm experiencing the same issue and wondering if the suggestion for making manual edit to the .js file would resolve it.

@EisenbergEffect
Blue Spire member
@iBoonz

I grabbed the files, replaced all durandal scripts (plugins / transitions / and root files) but i still have the problem.

If I disable the transition I have no problem, but when I enable transition and disable cache, the view goes blank after clicking to fast.

Maybe it helps: if I check the DOM, the last clicked view is still loaded, but its hidden (css: display:none), if I click on other router elements, they are not loaded anymore

@EisenbergEffect
Blue Spire member
@EisenbergEffect
Blue Spire member

Fixed (as far as I can tell) in branch Version-2.0.1.

@iBoonz

Yup its fixed, thanks! :)
👍

@rwhepburn

Awesome, I'll confirm tonight.

@gitmar

I've a problem that seems participate to this issue. I use durandal version 2.0.1 and navigate from a child view to another by calling router.navigate and its not work properly : sometimes the previous view stay on screen and I have 2/3 views opened at the same time.

@damiandennis

Yeah I have this happening without transitions as well but its harder to make happen. lots of random fast clicking. Its possible its the way I have implemented the routing maybe?

@damiandennis

Ok seems like its due to a redirect in my canActivate, if I redirect and click really fast on another link it breaks the navigation. Is there anyway to add delays between navigation. I have been using knockout a lot recently in a site that is not a single page application and usually I would put a isLoading observable that I would use to prevent such actions but can not figure out how to do it so far in Durandal.

@damiandennis

I also have a dynamically created childRouter so I am not sure if that is causing the issue also in some way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment