Angular calls ngOnInit only on components which have it build-time
Today I found a funny peculiarity in the ngOnInit
handling in Angular.
Perhaps you’ve thought of setting ngOnInit
dynamically on a component with a decorator like:
export function Magic(): PropertyDecorator {
return function(target: any): void {
target.ngOnInit = function(): void {
console.log('Hello!')
};
};
}
Which will be used like this:
@Component({...})
export class SomeComponent {
@Magic()
foo: string;
}
Unfortunately, that won’t work with the AOT compiler on components without ngOnInit
, like the one from the example.
The reason is that Angular core guards the ngOnInit
call with code like this:
if ((def.flags & NodeFlags.OnInit) &&
shouldCallLifecycleInitHook(view, ViewState.InitState_CallingOnInit, def.nodeIndex)) {
directive.ngOnInit();
}
In other words, the ngOnInit
we set with the decorator won’t be called without the NodeFlags.OnInit
flag, emitted by the AOT compiler telling whether SomeComponent
implements OnInit
.
The Magic
decorator will work in AOT only if you actually have an OnInit
method:
@Component({...})
export class SomeComponent implements OnInit {
@Magic()
foo: string;
ngOnInit(): void {
// You don't need anything here.
}
}
The solution? I just opted out from lifecycle hooks, relying on another approach :)