Skip to content
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

Closed
wants to merge 4 commits into from

Conversation

marclaval
Copy link
Contributor

The goal of this PR is to support lifecycle hooks of ViewContainerRef.
The 2 main changes:

  • the refreshDirectives method has been renamed refreshView and now includes the call to refreshDynamicChildren 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: calling refreshView, call view hooks, setting creationMode 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.

@marclaval marclaval added action: review The PR is still awaiting reviews from at least one requested reviewer target: major This PR is targeted for the next major release comp: ivy labels Apr 16, 2018
@mary-poppins
Copy link

You can preview f0d1403 at https://pr23396-f0d1403.ngbuilds.io/.

@mary-poppins
Copy link

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;
Copy link
Member

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.

@mary-poppins
Copy link

You can preview 827bd2e at https://pr23396-827bd2e.ngbuilds.io/.

@mary-poppins
Copy link

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 {
Copy link
Contributor

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

Copy link
Contributor Author

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(
Copy link
Contributor

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)

Copy link
Contributor Author

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be -> is ?

Copy link
Contributor Author

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. */
Copy link
Contributor

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 ?

Copy link
Contributor Author

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);
Copy link
Contributor

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);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@mary-poppins
Copy link

You can preview 788de25 at https://pr23396-788de25.ngbuilds.io/.

@mhevery
Copy link
Contributor

mhevery commented Apr 19, 2018

@kara could you review this.

@mhevery mhevery requested a review from kara April 19, 2018 17:39
Copy link
Contributor

@kara kara left a 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();
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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
Copy link
Contributor

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 ?

Copy link
Contributor Author

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);
Copy link
Contributor

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?

Copy link
Contributor Author

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.

Copy link
Contributor

@kara kara Apr 24, 2018

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
Copy link
Contributor

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');
Copy link
Contributor

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@mary-poppins
Copy link

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually returns void

Copy link
Contributor

@vicb vicb left a 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).

@mary-poppins
Copy link

You can preview 8dc9705 at https://pr23396-8dc9705.ngbuilds.io/.

@marclaval marclaval added action: merge The PR is ready for merge by the caretaker and removed action: review The PR is still awaiting reviews from at least one requested reviewer labels Apr 25, 2018
Copy link
Contributor

@IgorMinar IgorMinar left a 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

@IgorMinar
Copy link
Contributor

    http://test/OCL:194312401:BASE:194313007:1524697346415:f5b35693

@IgorMinar IgorMinar closed this in 1a44a0b Apr 26, 2018
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 13, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes target: major This PR is targeted for the next major release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants