39

I am using ionic 2.

I need to get HTML element value.

Actually, I used viewchild.

Here is my html template code

<div class="messagesholder" *ngFor="let chat of chatval | orderby:'[date]'; let last = last">
       {{last ? callFunction() : ''}} 

   <div *ngIf="chat.sender == currentuser || chat.receiver == currentuser">    
     <p class="chat-date"  id="abc" #abc>{{chat.date | amDateFormat:'LL'}}</p>                 
              {{checkdate()}}                         
   </div>

chat.date value is firebase value. I access this element. But I didn't get the value of the element.

Here is my component

import {Component, ElementRef,ViewChild, OnInit} from '@angular/core';

    export class ChatPage   {
      @ViewChild(Content) content: Content;
      @ViewChild('abc')abc: ElementRef;
       constructor(){}

      ngAfterViewInit(){

       console.log("afterinit");
       console.log(this.abc.nativeElement.value);

      }
    }

I referred this link How can I select an element in a component template?

I tried in many ways.

But I am getting this error

Cannot read property 'nativeElement' of undefined.
ANISUNDAR
  • 787
  • 5
  • 12
  • 28

8 Answers8

66

I think you are tring to get the value from html before rendering completely. If you try to print the value in a button click, it will works.

depend on your code I have modified a little.Try the below, it is working for me.

  ngAfterViewInit() {
    console.log("afterinit");
    setTimeout(() => {
      console.log(this.abc.nativeElement.innerText);
    }, 1000);
  }

Note: If not working, please increase the timeout time and try again.

Sabari
  • 1,963
  • 1
  • 13
  • 10
  • @sabari.Thank u so much.It's work.But i have one doubt.Kindly check my code.I was update my code.{{chat.date}} value using ngfor. I need changes the chat.date value. – ANISUNDAR Apr 13 '17 at 05:40
  • I will try to help you. But I didn't understood, what you want todo. Could you please explain it. – Sabari Apr 13 '17 at 06:24
  • 1
    this answer should be added to the angular doc's, half a day I've wasted trying to figure out why innterText and many other properties of nativeElement are empty or null. – Daniel Netzer Feb 22 '18 at 08:36
  • 11
    This is not a good solution, as the problem lies with the *ngIf statements and the component lifecycle. If the canvas is in the DOM, ngAfterViewInit should be able to assign the element ref, but again, setting timeouts is a hack, completely untestable, and a horrible practice. – Joshua Michael Calafell Jun 17 '20 at 19:30
  • Hi, I tried increasing the timeout time in angular 9, still the error persists – Deeksha Mulgaonkar Jun 03 '21 at 04:22
  • @JoshuaMichaelCalafell and what do you propose ? – Ivan Juarez Apr 13 '22 at 20:42
  • 1
    @Ivan-Juarez I propose never using `setTimeout(() => {})` for anything other than UX reasons, but even then, I don't think it's a good practice. I won't go too far into it, but all servers are running at different efficiencies, and if you're running same code on multiple computers, who's to say that the timeout time is going to work? That's why it's bad practice... Almost any time I see it used, it's either a cop out for a race case, or an avoidance of dealing with asynchronous data in a proper way ,or an avoidance of not understanding lifecycle hooks and implementing them appropriately. – Joshua Michael Calafell Apr 14 '22 at 17:36
  • @JoshuaMichaelCalafell that is so true, greetings! – Ivan Juarez Apr 18 '22 at 22:46
10

you can use the ElementRef in conjunction with @ViewChild if you do the following

HTML Markup:

<input type="text" class="form-control" #someNameInput>
<button
  class="btn btn-primary"
  (click)="clickMe()">Click Me</button>

In the Component Code:

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

For older version it's

@ViewChild('someNameInput') someNameInput: ElementRef;

Right before the constructor() method

And here is how you would use it in a function

clickMe(){
console.log(this.someNameInput.nativeElement.value);

}

If you get some value is undefined, it's usually means that it's a JavaScript issue and you don't have something initialized. Try and take ViewChild out of the equation first and make sure the code works without it first. Then introduce ViewChild into the mix. Kind of like testing your API with postman first then doing the Angular code later. Make sure that backend works first then you know for sure it's the Angular code. Angular has different page life cycles so some values are only available in the onAfterViewInit event and not on other events. So you have to play around with the view cycles. Haven't tried it but I suspect that if you try to get the value of the ViewChild in the ngOnInit method you will get an error or a blank value.

techjunkie
  • 171
  • 1
  • 4
2

The best lifecycle hook to use is AfterContentInit, allow all of the html content (such as the #map_canvas div) to be found by the scripts.

import { AfterContentInit, ViewChild } from '@angular/core';

Also, some updates have been made to ViewChild, it now takes a 2nd parameter:

@ViewChild('map_canvas', {static: false}) map_canvas: ElementRef;

Now you can use that hook to initialize your map:

ngAfterContentInit() {
    this.loadMap();
}
Grant
  • 5,709
  • 2
  • 38
  • 50
  • 3
    This will not work for Angular 7 and below. Since `@ViewChild` in Angular 7 does not accept `{static: false}` as second parameter. Only possible for Angular 8. – Olakunle Awotunbo Jan 23 '20 at 11:03
  • 2
    Still getting the same error after using `ngAfterContentInit()`. – Vidip May 19 '20 at 01:14
  • will still get the same error as in ngAfterViewInit(). This works only with a timer as suggested by the accepted answer. – Future2020 Jun 12 '20 at 09:50
2

Note for those who wonder, when using ViewChild in newer Angular (8+) you might get this error if you are trying to use ViewChild on a dynamically rendered object while using static flag.

example: @ViewChild('someSection',{ static: false }) someSection: ElementRef;

The { static: true } option was introduced to support creating embedded views on the fly. When you are creating a view dynamically and want to acces the TemplateRef, you won't be able to do so in ngAfterViewInit as it will cause a ExpressionHasChangedAfterChecked error. Setting the static flag to true will create your view in ngOnInit.

Credit to Poul Krujit here for pointing this out: How should I use the new static option for @ViewChild in Angular 8?

qubits
  • 1,227
  • 3
  • 20
  • 50
2

Instead use a class to show/hide your element being hidden.

<div [class.show]="boolean">...</div>

@viewChild not working - cannot read property nativeElement of undefined

0

Do not specify the type of variable abc. It should be like below:

 @ViewChild('abc') abc;
Yuvraj Patil
  • 7,944
  • 5
  • 56
  • 56
  • 6
    The type in this case doesn't change anything at all during runtime unfortunately. – Amit Apr 13 '17 at 08:05
0

declare Child component's selector into the Parent component html template. Otherwise, component object abc will not be initialized at runtime to call its functions or public properties at the parent.ts file.

Child Component abc:

@Component({
    selector: 'child-abc',
    templateUrl: './abc.component.html',
    styleUrls: ['./abc.component.css'],
})

At parent Component's html template declare child's selector:

< child-abc > < /child-abc >
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
-2

I think you should move your code from ngAfterViewInit to ngOnInit in order to avoid such kind of issues and not rely on timeout:

ngOnInit(){
  console.log("afterinit");
  console.log(this.abc.nativeElement.value);   
}
Prerak Tiwari
  • 3,436
  • 4
  • 34
  • 64