New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ivy): support lifecycle hooks of ViewContainerRef #23396
Conversation
You can preview f0d1403 at https://pr23396-f0d1403.ngbuilds.io/. |
f0d1403
to
eea7834
Compare
You can preview eea7834 at https://pr23396-eea7834.ngbuilds.io/. |
it('should call all hooks in correct order', () => { | ||
@Component({selector: 'hooks', template: `{{name}}`}) | ||
class ComponentWithHooks { | ||
name: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is missing an @Input
decorator. Although it won't have any effect, it will make the ngComponentDef
in line with the decorators.
eea7834
to
827bd2e
Compare
You can preview 827bd2e at https://pr23396-827bd2e.ngbuilds.io/. |
827bd2e
to
8015e38
Compare
You can preview 8015e38 at https://pr23396-8015e38.ngbuilds.io/. |
if (!checkNoChangesMode) { | ||
executeHooks( | ||
directives !, currentView.tView.viewHooks, currentView.tView.viewCheckHooks, creationMode); | ||
export function leaveView(newView: LView, creationOnly?: boolean): void { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add API docs for the new parameter
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
export function leaveView(newView: LView, creationOnly?: boolean): void { | ||
if (!creationOnly) { | ||
if (!checkNoChangesMode) { | ||
executeHooks( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an assert in executeHooks ? (!checkNoChangesMode
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
checkNoChangesMode
is not accessible in executeHooks
, I don't think we want to pass it or add a dependency
directives !, currentView.tView.viewHooks, currentView.tView.viewCheckHooks, | ||
creationMode); | ||
} | ||
// Views should be clean and in update mode after being checked, so these bits are cleared |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be -> is ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
function refreshDirectives() { | ||
executeInitAndContentHooks(); | ||
|
||
/** Refreshes the view: dynamic children and directives, triggering any init/content hooks. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
expand the comment a little bit ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
} finally { | ||
leaveView(oldView !); | ||
leaveView(oldView !, (rf & RenderFlags.Create) === RenderFlags.Create); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion:
// comment ?
const creationMode = (rf & RenderFlags.Create) === RenderFlags.Create;
leaveView(oldView !, creationMode);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
You can preview 788de25 at https://pr23396-788de25.ngbuilds.io/. |
@kara could you review this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some nits and a question
currentView.lifecycleStage = LifecycleStage.Init; | ||
currentView.bindingIndex = -1; | ||
enterView(newView, null); | ||
} | ||
|
||
/** Refreshes directives in this view and triggers any init/content hooks. */ | ||
function refreshDirectives() { | ||
executeInitAndContentHooks(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're removing this usage, we should probably remove the executeInitAndContentHooks
function and inline it. I think it's only used in one other place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is still used in 2 different places: renderComponent
and renderComponentOrTemplate
. If this can be refactored, let's do it in a future PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aha, forgot to check component.ts
. In that case, sg.
* | ||
* @param newView New state to become active | ||
* @param creationOnly An optional boolean to indicate that the view was processed in creation mode | ||
* only, i.e. the first update will be done later |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Maybe clarify to indicate that the separate modes occur for dynamically created views ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
creationMode); | ||
} | ||
// Views are clean and in update mode after being checked, so these bits are cleared | ||
currentView.flags &= ~(LViewFlags.CreationMode | LViewFlags.Dirty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like we should be clearing the creation flag whenever we leave a view, even if we are creationOnly. Otherwise, the creation flag would be on for the update mode check that comes next. Can you clarify why it should be in creation mode for both runs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the first update is not done with the CreationMode flag still on, then the onInit
, afterContentInit
and afterViewInit
hooks are never called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks for explaining, I get what you're doing now.
My only concern is that the RenderFlags
and ViewFlags
are sometimes out of sync. The second time through, we are in update mode according to RenderFlags
, but we are still in creation mode according to ViewFlags
. What do you think about keeping the view flags in sync (by clearing the creation mode in ViewFlags
), but using the existing lifecycleStage
property to track hooks?
If that doesn't work, okay to keep it as is, as long as we add a comment/TODO explaining the discrepancy.
@@ -2436,6 +2436,90 @@ describe('lifecycles', () => { | |||
|
|||
}); | |||
|
|||
// Angular 5 reference: https://stackblitz.com/edit/lifecycle-hooks-ng |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great idea to include a stackblitz example in a comment 👍
function Template(rf: RenderFlags, ctx: any) { | ||
if (rf & RenderFlags.Create) { | ||
elementStart(0, 'parent'); | ||
elementStart(1, 'content'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: any reason why we're not indenting the inner ones to make it a little easier to read?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
788de25
to
331902c
Compare
You can preview 331902c at https://pr23396-331902c.ngbuilds.io/. |
* @param newView New state to become active | ||
* @param creationOnly An optional boolean to indicate that the view was processed in creation mode | ||
* only, i.e. the first update will be done later. Only possible for dynamically created views. | ||
* @returns the previous state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually returns void
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@marclaval please fix the return type (should be void).
331902c
to
8dc9705
Compare
You can preview 8dc9705 at https://pr23396-8dc9705.ngbuilds.io/. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm for the json file changes.
@kara please send the PR to exclude these
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
The goal of this PR is to support lifecycle hooks of ViewContainerRef.
The 2 main changes:
refreshDirectives
method has been renamedrefreshView
and now includes the call torefreshDynamicChildren
so that it can be correctly done between init hooks calls and content hooks calls, as in Angular today.renderEmbeddedTemplate
is called twice: once in creation mode only and once in update mode only. This has to be taken into account as a few things must be done during/after the first update: callingrefreshView
, call view hooks, settingcreationMode
to false.The extra test in lifecycle_spec.ts is to to ensure that the new engine correctly handles lifecycle hooks when there is a component in the content.