Using @ViewChild to get hold of the .nativeElement of an input returns 'undefined'
Just add another template variable
#foobar="ngForm" #foobarElement
@ViewChild("foobarElement") foobar: ElementRef;
With ="ngForm"
the template variable gets a different purpose and doesn't work with @ViewChild()
If you think this should still work, consider creating a bug report.
XDS
Updated on July 23, 2022Comments
-
XDS almost 2 years
I created the following form in angular2:
import {Component, ElementRef, ViewChild, AfterViewInit} from "angular2/core"; import {Observable} from "rxjs/Rx"; import {ControlGroup, Control, Validators, FormBuilder} from "angular2/common"; @Component({ selector: "ping-pong", template: ` <form name="someform" [ngFormModel]="form"> <div class="form-group"> <input id="foobar" #foobar="ngForm" <-- without ="ngForm" everything works fine type="text" ngControl="foobar" value="" class="form-control" /> </div> </form> `, styles: [` form { width: 300px; } `] }) export class ChangepswdFormComponent implements AfterViewInit { @ViewChild("foobar") foobar: ElementRef; private form: ControlGroup; public constructor(formBuilder: FormBuilder) { this.form = formBuilder.group({ foobar: [""] }); } public ngAfterViewInit(): void { console.log(this.foobar.nativeElement); //observable doesnt work because nativeelement is undefined //Observable.fromEvent(this.foobar.nativeElement, "keyup").subscribe(data => console.log(data)); } }
Inside ngAfterViewInit the nativeElement bit is undefined unless I remove the = "ngForm" part from #foobar = "ngForm".I overcame this problem by making the following tweaks:
import {Component, ElementRef, ViewChild, AfterViewInit} from "angular2/core"; import {Observable} from "rxjs/Rx"; import {ControlGroup, Control, Validators, FormBuilder} from "angular2/common"; @Component({ selector: "ping-pong", template: ` <form name="someform" [ngFormModel]="form"> <div class="form-group"> <input id="foobar" #foobar="ngForm" #tralala type="text" ngControl="foobar" value="" class="form-control" /> </div> </form> `, styles: [` form { width: 300px; } `] }) export class ChangepswdFormComponent implements AfterViewInit { @ViewChild("tralala") foobar: ElementRef; private form: ControlGroup; public constructor(formBuilder: FormBuilder) { this.form = formBuilder.group({ foobar: [""] }); } public ngAfterViewInit(): void { console.log(this.foobar.nativeElement); let keyups = Observable.fromEvent(this.foobar.nativeElement, "keyup"); keyups.subscribe(data => console.log(data)); } }
In other words I enriched the input element with an auxilary hashtag (#tralala) which is not related to ngForm.Even though this solution works I don't feel at ease with it because it feels like I'm applying a small hack. We should somehow be able to retrieve the native element of the textbox in a more elegant/straightforward way either through @ViewChild or through this.form.controls (or something to that effect) WITHOUT resorting to workarounds like the one I used. But I can't figure out exactly how.
Quick Addendum: I'm using Angular2 2.0-beta7 if that's of any importance.
-
XDS over 7 yearsThanks for tuning in. As I already mentioned I tried this approach and it worked indeed. However (as have also already stated) I find the approach a bit ... counter-intuitive.
-
Günter Zöchbauer over 7 yearsWhat to you expect to get from
@ViewChild()
in this case? The element where the template variable is added (<input>
), to orngForm
directive, that is assigned to the variable? -
XDS over 7 yearsI have update the wording to emphasize my goal: "We should somehow be able to retrieve the native element of the textbox in a more elegant/straightforward way either through @ViewChild or through this.form.controls (or something to that effect) WITHOUT resorting to workarounds like the one I used." <- I'm refering to the auxilary-tag workaround I used - just because it works it doesn't mean it's elegant or the "canon" way of doing things in Angular2 (yeah I know I'm a perfectionist :) )
-
Günter Zöchbauer over 7 yearsNo idea why you think it's a workaround. This is how you get a reference to an element in Angular2. You assign the
NgForm
directive to the template variable, therefore it doesn't seem right to me that@ViewChild()
should return the<input>
element instead. -
XDS over 7 yearsPoint taken. I'm still having some doubts though because I would like more people to confirm your point of view before I adopt it.
-
David Barker over 6 yearsIt's not just his point of view, this is how it was designed and makes sense to me.