Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 - How to access a child input element which is yet to be rendered?

Tags:

angular

For example, my template looks like -

<div #parent>
    <button (click)="showInput()"> Show </button>
    <input #inp *ngIf="showInpField" />
</div>

And this is how my compoent looks like:

import { Component, OnInit, ViewChild } from '@angular/core';
@Component({
  selector: 'some-component',
  templateUrl: './template.html',
})
export class SomeComponent {
    @ViewChild('inp') inpField: any;
    showInpField = false;
    constructor() {}
    showInput(){
        this.showInpField = true;
        // This doesn't work
        this.qaTitle.inpField.focus();
    }   
}

In this case the focus doesn't work because the input element is still yet to be render. I realize that using timeout on that line will work, but somehow I don't feel like it's a good way to do it.

I guess somehow I have detect the change inside the parent div, and on that event I should do the focus operation. How would I do that? I feel like QueryList can be helpful but I can't figure out how do I use it in this case!

like image 437
user1532043 Avatar asked Dec 01 '16 12:12

user1532043


People also ask

What is the use of @input in angular?

@Input () is basically a decorator to bind a property as an input. It is used to pass data i.e property binding from one component to other or we can say, from parent to child component. It is bound with the DOM element. When the DOM element value is changed, Angular automatically updates this property with the changed value.

What is viewchild in Angular 2?

The parent component was able to set the value of the child DOM Element. ViewChild makes it possible to access a child component and call methods or access instance variables that are available to the child. Let’s say we have a ChildComponent. Ideally, you will use @angular/cli to generate your component:

How to send data to parent from child in Angular 2?

The Child can send data to Parent by raising an event, Parent can interact with the child via local variable or Parent can call @ViewChild on the child. We will look at all those options in this article. Applies to: Angular 2 to the latest edition of i.e. Angular 8. Angular 9, Angular 10, Angular 11, Angular 12

What is the use of angular component?

So we can consider angular component as a way to create custom element and directive as a custom attribute. (for now) An attribute/tag become a child of another if that is used inside the other tag's component html. Child can pass some data to parent via event binding.


2 Answers

This could work

@Component({
  selector: 'my-app',
  template: `
    <div>
      <button (click)="toggleInput()"> {{ showInpField ? 'Hide' : 'Show'}} </button>
      <input #inp *ngIf="showInpField" />
  </div>
  `
})
export class AppComponent { 
  @ViewChildren('inp', { read: ElementRef }) elemRefs: QueryList<ElementRef>;

  showInpField = false;

  constructor(private renderer: Renderer){}

  toggleInput(){
    this.showInpField = !this.showInpField;
  }  

  ngAfterViewInit() {
    this.elemRefs.changes.subscribe(item => {
      if(!this.elemRefs.length) return;

      this.renderer.invokeElementMethod(this.elemRefs.first.nativeElement, 'focus');
    })
  } 
}

Plunker Example

like image 105
yurzui Avatar answered Oct 03 '22 00:10

yurzui


Official way would be to use the Renderer!

https://angular.io/docs/ts/latest/api/core/index/Renderer-class.html

import {Component, NgModule, Renderer, ViewChild} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2 (click)="toggleInput()">Hello {{name}}</h2>
      <input value="any other input.." />
      <br />
      <input #inpt *ngIf="showInput" />
    </div>
  `,
})
export class App {
  @ViewChild('inpt') input;
  name:string;
  showInput = false;

  constructor(private _renderer: Renderer) {
    this.name = 'Angular2'
  }

  private toggleInput() {
    this.showInput = !this.showInput;

    if (this.showInput) {
      setTimeout(() => {
        this._renderer.invokeElementMethod(this.input.nativeElement, 'focus');
      }, 1);
    }
  }
}

@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

live demo: https://plnkr.co/edit/DWaEvqjFARRsKg1Byeu7?p=preview

like image 32
slaesh Avatar answered Oct 03 '22 00:10

slaesh