aurelia / templating-router

An implementation of the RouteLoader interface for use with the router module. Also contains a custom element that allows the templating engine to display the current route.
MIT License
26 stars 40 forks source link

Parent views containing a router-view should be able to render before child activate promise resolves #26

Open briannoyes opened 8 years ago

briannoyes commented 8 years ago

With the latest code, if a child view placed into router-view within a parent view returns a promise from its activate method, the parent is not rendered until the child promise completes. For a shell view containing a router-view for its main content area, it would be pretty normal to show the shell and even let the user interact with it to possibly select a menu or view information in another child view while the child view in the router-view is loading (and probably showing some kind of progress indicator in the shell or in the main content area. With the current code that does not appear to be possible.

paulharker commented 8 years ago

Hi Rob and Team, I agree with Brian, if we are loading our child template with a promise, I would like to load my "shell" with a wireframe (like Facebook does) until my content comes in.

EisenbergEffect commented 8 years ago

We can enable it by adding a new property on the router-view.

briannoyes commented 8 years ago

Sounds like a straightforward approach to me. Not saying it has to be the default behavior, just want a simple approach to opt in to that behavior.

rajajhansi commented 8 years ago

@EisenbergEffect I agree with Brian. This issue doesn't shows up in skeleton-navigation because the progress indicator is wired in index.html even before the shell (i.e. app.html/.js) is loaded. Even there, for every navigation the full page "AURELIA SKELETON NAVIGATION" with an AJAX progress shows up, which becomes annoying after a point. I remember seeing a youtube style progress bar (like this: http://ricostacruz.com/nprogress/ ) down below the top navigation menu in earlier aurelia samples, which was much better.

fkleuver commented 6 years ago

I know this has been sitting in limbo for a while, but afaik we still don't have a way to do this.

I'm very interested in having an opt-in for viewmodels to start rendering immediately after they activate, rather than waiting for all activates to resolve.

@EisenbergEffect you mention a property, but as far as I understand it the router in principle won't kick off the rendering process before aurelia knows precisely what to render (which is after all CommitChangesSteps have run), and then the rendering happens inside-out.

I've visualized this by proxying everything through a logger, and put a 300ms promise delay in the viewmodel activate functions to simulate some loading time. view-model 1 (and router-view 1) is the root.

35.298 [-view-model 1] activate
35.337 [-view-model 1] configureRouter
35.346 [-router-view 1] created
35.353 [-view-model 1] created
35.362 [-view-model 1] bind
35.377 [-router-view 1] bind
35.400 [--view-model 2] configureRouter
35.407 [---view-model 3] configureRouter
35.414 [----view-model 4] configureRouter
35.422 [--view-model 2] activate
35.726 [---view-model 3] activate
36.030 [----view-model 4] activate
36.335 [-router-view 1] process
36.351 [--router-view 2] created
36.359 [--router-view 2] process
36.366 [---router-view 3] created
36.371 [---router-view 3] process
36.377 [----router-view 4] created
36.381 [----router-view 4] process
36.393 [----router-view 4] swap
36.397 [---router-view 3] swap
36.401 [----view-model 4] created
36.404 [----view-model 4] bind
36.409 [----router-view 4] bind
36.413 [--router-view 2] swap
36.418 [---view-model 3] created
36.422 [---view-model 3] bind
36.426 [---router-view 3] bind
36.431 [-router-view 1] swap
36.435 [--view-model 2] created
36.439 [--view-model 2] bind
36.444 [--router-view 2] bind
36.451 [----router-view 4] _notify
36.454 [---router-view 3] _notify
36.455 [--router-view 2] _notify
36.455 [-router-view 1] _notify
36.458 [-view-model 1] attached
36.469 [--view-model 2] attached
36.471 [---view-model 3] attached
36.472 [----view-model 4] attached

After the last activate resolves, the entire rendering process of all pages happens in about 137ms. This means that with most webapi-ish delays in resolving an activate, a page can easily be rendered before the next activate resolves.

Currently the only way around this as being a constant, is by aggressively caching stuff on the client which makes initial load times for data-driven navigations even slower.

The pipeline steps seem to run (for the most part) one-by-one per type and there's no way around this without changing the pipeline. What's needed for this is an opt-in such that activate 2 still has to wait for activate 1 to resolve, but commitChanges 1 doesn't have to wait for activate 2 to resolve.
I'm thinking two possible approaches here:

  1. Allow for a different router pipeline implementation to be used
  2. Extend the existing router pipeline with something like "pipelineRunStrategy"

But it's not just a router concern, because the composition engine has to know that it should delay processing for a router-view whose child activation lifecycle has not completed yet. Rather than a fully inside-out rendering process, you'd have a multiple-passes rendering process.

I feel like I'm insane for suggesting to have a stab at this, but I need it. Is this something you think can be done?

davismj commented 6 years ago

@fkleuver why not just resolve the child activate immediately, then?

fkleuver commented 6 years ago

@davismj Because activate, as far as I know, is the proper place to wait for server data to load.

Resolving that before the server data is loaded I need to pollute my custom elements with all kinds of "is the data there yet?" checks to delay rendering until it is.

Which is really what I'm hoping (and typically advise other people) to avoid in favor of awaiting the loading during activate.

If the router can neatly handle postponing page rendering until activates are resolved, but allows a resolved parent activate to start the rendering of that parent before the child activate is resolved, then that would be a router that just scratches the itch.

Alexander-Taran commented 6 years ago

@fkleuver how you you handle long loads? do you not show some spinner/progress?

fkleuver commented 6 years ago

@Alexander-Taran Currently you can only do that in the top-level page of where the navigation starts which, in case of a full page load, is the index.html. Let me show you an example:

https://fkleuver.github.io/aurelia-recursive-navigation-sample/#/

davismj commented 6 years ago

@fkleuver excellent ideas as always, Fred.

fkleuver commented 6 years ago

@davismj I don't know what idea you're referring to, but I'm still kind of clueless on how to approach this without changes to router, templating-router and templating that would probably give the team a heart attack. Maybe this should be left for vNext..