Raman
Raman

Reputation: 353

unable to access template reference variable inside *ngIf

I am getting the following error displayed in screenshot. enter image description here

When I click the search link, I am displaying the search input, I am using keyup event to get values from input. But getting the error shown in screenshot. I am using angular 6.

component

import { Component, OnInit, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { fromEvent } from 'rxjs';
import { map } from 'rxjs/operators';

@Component({
  selector: 'app-temp',
  templateUrl: './temp.component.html',
  styleUrls: ['./temp.component.css']
})
export class TempComponent implements OnInit, AfterViewInit {
  displaySearch = false;
  @ViewChild('searchValue') searchValue: ElementRef;
  constructor() { }

  ngOnInit() {
  }

   searchFunc() {
      if (this.displaySearch === false) {
          this.displaySearch = true;
      } else if (this.displaySearch === true){
          this.displaySearch = false;
   }

}

  ngAfterViewInit() {
    fromEvent(this.searchValue.nativeElement, 'keyup').pipe(
      map((event: any) => {
        return (event.target).value;
      })
    ).subscribe(res => {
      console.log(res);
    });
  }
}

Html

<div>
  <a href="javascript:void(0)" (click)="searchFunc()">Search</a>
</div>

<ng-container *ngIf="displaySearch">
  <input type="text" name="searchValue" #searchValue>
</ng-container>

Upvotes: 1

Views: 1777

Answers (2)

SiddAjmera
SiddAjmera

Reputation: 39432

That's kinda expected.

ngAfterViewInit would run right after the view gets initialized. And your searchValue template variable comes in view, only after clicking on the Search link. And in the ngAfterViewInit method, you're trying to read nativeElement on something, which at that moment, would be undefined.

Hence the error.

UPDATE:

By reading the data from @ViewChild you're making it unnecessarily difficult for yourself.

How about just listening to the keyup event on the input field using the event binding syntax:

<div *ngIf="displaySearch">
    <input 
    type="text" 
    name="searchValue" 
    (keyup)="onKeyUp($event.target.value)" />
</div>

And you'll get the value in the onKeyUp method.

NOTE: The Solution suggested by Vega, is a great solution too. But it won't scale well. Since the ngAfterViewChecked method gets called on every change detection cycle. So I won't recommend using that.


Here's a Working Sample StackBlitz for your ref.

Upvotes: 1

Sudarshana Dayananda
Sudarshana Dayananda

Reputation: 5265

You cannot use this.searchValue.nativeElement in ngAfterViewInit(). The reason is when TempComponent is loading searchValue input is not in the DOM as displaySearch is false at that time. You should use nativeElement after displaySearch becomes true. change your code as follows.

   searchFunc() {
    this.displaySearch = true;
    setTimeout(() => {

    fromEvent(this.searchValue.nativeElement, 'keyup').pipe(
      map((event: any) => {
        return (event.target).value;
      })
    ).subscribe(res => {
      console.log(res);
    });

    },3000);
  }

Upvotes: 2

Related Questions