I can find nothing that tells me the order of the components lifecycle with respect to other components.
See https://aurelia.io/docs/fundamentals/creating-components#the-component-lifecycle
Nor how the routing lifecycle is interweaved with the component lifecycle.
See https://aurelia.io/docs/fundamentals/cheat-sheet#routing
The best I can find is related to Dialogs.
See https://aurelia.io/docs/plugins/dialog#lifecycle-hooks
Order of Invocation
Each dialog instance goes through the full lifecycle once.
constructor call
.canActivate() - aurelia-dialog specific
.activate() - aurelia-dialog specific
.created() - as defined by aurelia-templating
.bind() - as defined by aurelia-templating
.attached() - as defined by aurelia-templating
.canDeactivate() - aurelia-dialog specific
.deactivate() - aurelia-dialog specific
.detached() - as defined by aurelia-templating
.unbind() - as defined by aurelia-templating
If I’m trying to share application state I need to know which component should be creating that state.
My current assumption was that custom elements higher up in the DOM would have their lifecycle called first so that its children would have whatever was needed by the time it was their turn for the lifecycle events.
Whacking in some debugs is showing me:
- activate on Parent
- activate on Child
- created on Child
- bind on Child
- created on Parent
- bind on Parent
- attached on Parent
- attached on Child
I’ll have to ponder this some more.
What advice do you have for me?
If I have remote resources that need obtaining where is the correct place in the lifecycle to fetch them?
1 Like
Note the wrong order of bind (parent should be before child) is a know bug (introduced by a fix to another bug).
That’s not the only lifecycle ordering bug, there is another one in child route https://github.com/aurelia/router/pull/571.
It was left as it is, because of current router has no enough test coverage. We are afraid of introducing another bug from another fix.
On the other side, Aurelia 2 has made it deadly clear about the lifecycle orders in test cases.
1 Like
In router components, I do remote fetch in activate.
In other custom elements, I do remote fetch in attached.
You can return a promise in all callbacks.
When remote fetch is slow, I recommend to have a global spinner, so that you don’t have to do spinner in every single route pages.
In top template (like app.html
). debounce
means you don’t show spinner if it’s quicker than 200ms (default debounce delay).
<my-spinner
if.bind="router.isNavigating || fetchClient.isRequesting & debounce"
></my-spinner>
2 Likes
Where is the return a promise in all callbacks
documented?
I know activate
supports that because https://aurelia.io/docs/fundamentals/cheat-sheet#routing says so.
I’m sure I tried returning a Promise for other callbacks and it wasn’t working as I thought it might, and since I couldn’t find the docs to say otherwise I assumed Promises were not await
ed on.
Thanks for your thoughts, I’ll ponder what I should do properly some more.
1 Like
I could not find proper document either @bigopon do you know is this documented?
They do accept promise return, Aurelia will wait for them. This is a nice feature since Durandaljs (although I did not use it) before Aurelia. Async/await is same, it is syntax sugar for promise. (I was all wrong )
Show me your code which wasn’t working as you thought.
1 Like
That code is long gone
I was hacking to see why things were not working the way I expected, which I assume is my lack of understanding rather than bugs.
1 Like
@huochunpeng
I’ve tried returning a Promise
from bind
expecting that to halt any further components bind
being called, or at the least to wait until resolving before moving on to the further steps in the lifecycle like attached
But its not.
I don’t have a small reproducible test case yet. If I can sort out my production code I’ll work on that after.
1 Like
You are right. I was wrong. It looks like bind did not wait on promise. I will check if this is intentional. For now, use attached to wait on remote fetch.
1 Like
The templating lifecycles have never awaited promises in v1, only the router lifecycles do. In v1 you normally fetch data in activate
rather than in bind
. It’s possible though with composition transactions.
In v2 you can return a promise from bind
and it will be awaited
1 Like
I was all wrong no wonder no documentation.
Only router lifecycle canActivate, activate, canDeactive, deactivate supports promise return.
I return promise in attached, but it actually renders before the promise is resolved.
1 Like
I wish I could find the damn web article. It’s something along the lines of ensuring you test your component when it doesn’t have data.
I know its the way our components are (poorly) written. Right now the component fetches from the server to retrieve the settings for the component, as we persist those settings and its changes.
I’ve got a place holder for Improving vCurrent docs and it may very well be the way I look at the lifecycle hooks, but because activate
doesn’t have anything injected into it and it hasn’t been created
I don’t think activate
is the correct place to fetch those values and then store them into the object as its not at the right stage in the lifecycle for touching member properties.
Yet if I don’t do it there the child components that depend on those settings won’t have anything available yet.
The code currently does the fetch and setting of this
member properties in the activate
and so I’m attempting to clean up the code and document what each lifecycle’s purpose is for and what types of things you should be doing in that method. We don’t have that level of understanding internally yet.
Note: My claim that it didn’t have anything injected into it was because it was a fresh restart of the server and the injected object hadn’t been setup yet. The constructor
is the first thing in the lifecycle, which includes all injected properties. Whether your code has setup those objects is your problem, not Aurelia’s.
1 Like
The route activate
callback is before created
and bind
, that is a debatable decision. But it doesn’t matter because you don’t have any binding on a route component.
The activate
callback is designed for you to fetch remote data before rendering route component. This is demonstrated in tutorial. https://aurelia.io/docs/tutorials/creating-a-contact-manager#building-out-the-contact-detail-screen
2 Likes
Its very likely that our component is doing too much and should be broken into 2 components.
One to do the routing, one to do UI.
That expert advice is definitely something I want to add to the documentation.
2 Likes
Could you explain this advice a bit more, how would a component look like that only does routing and no rendering?