Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ViewChild not working after upgrading to Angular 9

Tags:

angular

After upgrading to Angular 9, basically all my @ViewChild references are not initialized anymore.

No matter what,

<app-menu-editor #menuEditor>
</app-menu-editor>

<div #cardBody>
  <!-- ... -->
</div>
@ViewChild('menuEditor', {read: MenuEditorComponent}) menuEditor: MenuEditorComponent;

@ViewChild('cardBody', {read: ElementRef}) cardBody: ElementRef;

I keep getting exceptions telling me that e.g. menuEditor is undefined.

Any idea why this is not working anymore?

like image 716
Stefan Falk Avatar asked Feb 14 '20 16:02

Stefan Falk


People also ask

What does @ViewChild does in Angular?

The @ViewChild and @ViewChildren decorators in Angular provide access to child elements in the view DOM by setting up view queries. A view query is a requested reference to a child element within a component view which contains metadata of the element.

What is the difference between ViewChild () and ContentChild ()?

ViewChild is used to select an element from component's template while ContentChild is used to select projected content.

What is the difference between @ViewChild and @input?

While Angular inputs/outputs should be used when sharing data to and from child components, ViewChild should be used when trying to utilize properties and methods of the child component directly in the parent component.

Should you use ViewChild?

Conclusion. The @ViewChild decorator allows us to inject into a component class references to elements used inside its template, that's what we should use it for. Using @ViewChild we can easily inject components, directives or plain DOM elements.


3 Answers

Try

@ViewChild('menuEditor', {static: true, read: MenuEditorComponent}) menuEditor: MenuEditorComponent;

@ViewChild('cardBody', {static: true, read: ElementRef}) cardBody: ElementRef;

Like PierreDuc said, maybe you're referring to them in the ngOnInit.

like image 62
AliF50 Avatar answered Oct 28 '22 16:10

AliF50


I had another scenario with angular 9 that took me two days to figure out.

My problem was that none of the solutions worked; in fact, neither ViewChild nor ViewChildren worked in ANGULAR 9.

The issue, after A LOT of investigation and NO WARNS, was that my @ViewChild was on an ABSTRACT CLASS that WASN'T marked as a @Component.

So, if you're doing something like that:

export abstract class AbstractBaseComponent {
   @ViewChild('test') public testRef: TestComponent;
}

@Component({
   'selector': 'base-component'
})
export class BaseComponent extends AbstractBaseComponent {
    ngAfterViewInit() {
        console.log(this.testRef);
    }
}

THIS WON'T WORK. you must add @Component on the abstract class as well:

@Component({})
export abstract class AbstractBaseComponent {
   @ViewChild('test') public testRef: TestComponent;
}

Further reading about that can be (indirectly) found in the breaking changes in angular 9:

  • https://angular.io/guide/updating-to-version-9
  • https://angular.io/guide/deprecations#undecorated-base-classes

Although it's not mentioned that abstract classes follows the same behavior, it is actually intended to be as it is, since abstract classes are technically not transpiled.

like image 7
briosheje Avatar answered Oct 28 '22 15:10

briosheje


I am guessing that you are getting undefined either within the ngOnInit hook or inside of the class constructor. If my guess is correct then here's your problem:

A view child becomes available within ngOnInit if you use the static: true option inside the @ViewChild decorator. If static: true option is not set, then your view child only becomes available in ngAfterViewInit. The static options is set to false by default.

This SO answer may also be of help.

like image 5
Sam Herrmann Avatar answered Oct 28 '22 14:10

Sam Herrmann