Tutorial

Используйте ViewChild в Angular для доступа к дочернему компоненту, директиве или элементу DOM

Angular

Введение

В этой статье мы познакомим вас с декоратором Angular ViewChild.

В некоторых ситуациях вам может потребоваться доступ к директиве, дочернему компоненту или элементу DOM из класса родительского компонента. Декоратор ViewChild возвращает первый элемент, совпадающий с заданной директивой, компонентом или селектором шаблонов.

Использование ViewChild с директивами

ViewChild открывает возможность доступа к директивам.

Допустим, у нас имеется директива SharkDirective.

В идеале мы используем @angular/cli для генерирования директивы:

  • ng generate directive shark

В противном случае необходимо добавить ее вручную в app.module.ts:

app.module.ts
import { SharkDirective } from './shark.directive';
...
@NgModule({
  declarations: [
    AppComponent,
    SharkDirective
  ],
  ...
})

Наша директива будет искать элементы с атрибутом appShark и добавлять в начало текста элемента слово Shark:

shark.directive.ts
import {
  Directive,
  ElementRef,
  Renderer2
} from '@angular/core';

@Directive(
  { selector: '[appShark]' }
)
export class SharkDirective {
  creature = 'Dolphin';

  constructor(elem: ElementRef, renderer: Renderer2) {
    let shark = renderer.createText('Shark ');
    renderer.appendChild(elem.nativeElement, shark);
  }
}

Затем мы добавим Shark в Fin, используя его в шаблоне компонента:

app.component.html
<span appShark>Fin!</span>

При просмотре приложения в браузере оно будет выглядеть так:

Output
Shark Fin!

Теперь мы можем получить доступ к переменной экземпляра creature директивы SharkDirective и задать переменную экземпляра extraCreature с ее значением:

app.component.ts
import {
  Component,
  ViewChild,
  AfterViewInit
} from '@angular/core';
import { SharkDirective } from './shark.directive';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  extraCreature: string;

  @ViewChild(SharkDirective)
  set appShark(directive: SharkDirective) {
    this.extraCreature = directive.creature;
  };

  ngAfterViewInit() {
    console.log(this.extraCreature); // Dolphin
  }
}

Здесь мы использовали задающий метод, чтобы задать переменную extraCreature. Обратите внимание, что мы ждем, пока блок жизненного цикла AfterViewInit не получит доступ к нашей переменной, поскольку тогда станут доступными дочерние компоненты и директивы.

При просмотре приложения в браузере мы видим "Shark Fin!", сообщение. Однако в журнале консоли отображается следующее:

Output
Dolphin

Родительскому компоненту удалось получить доступ к значению из директивы.

Использование ViewChild с элементами DOM

ViewChild предоставляет возможность доступа к элементам модели DOM, имеющим шаблонную переменную.

Допустим в нашем шаблоне имеется <input> с шаблонной переменной #someInput:

app.component.html
<input #someInput placeholder="Your favorite sea creature">

Теперь мы можем получить доступ к <input> с помощью ViewChild и задать значение:

app.component.ts
import {
  Component,
  ViewChild,
  AfterViewInit,
  ElementRef
} from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
  @ViewChild('someInput') someInput: ElementRef;
  ngAfterViewInit() {
    this.someInput.nativeElement.value = 'Whale!';
  }
}

Когда срабатывает ngAfterViewInit, для <input> задается следующее значение:

Output
Whale!

Родительскому компоненту удалось задать значение дочернего элемента DOM.

Использование ViewChild с дочерними компонентами

ViewChild обеспечивает возможность доступа к дочернему компоненту и методам вызова или доступа к переменным экземпляра, которые доступны дочернему элементу.

Допустим, у нас имеется компонент ChildComponent. В идеале мы используем @angular/cli для генерирования компонента:

  • ng generate component child --flat

В противном случае вам может понадобиться создать файлы child.component.css и child.component.html и вручную добавить их в app.module.ts:

app.module.ts
import { ChildComponent } from './child.component';
...
@NgModule({
  declarations: [
    AppComponent,
    ChildComponent
  ],
  ...
})

Мы добавим метод whoAmI в компонент ChildComponent, который возвращает следующее сообщение:

child.component.ts
whoAmI() {
  return 'I am a child component!';
}

Далее мы разместим ссылку на компонент в нашем шаблоне приложения:

app.component.html
<app-child>child works!</app-child>

Теперь мы можем вызвать метод whoAmI внутри класса родительского компонента с помощью ViewChild, как показано здесь:

app.component.ts
import {
  Component,
  ViewChild,
  AfterViewInit
} from '@angular/core';
import { ChildComponent } from './child.component';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements AfterViewInit {
  @ViewChild(ChildComponent) child: ChildComponent;
  ngAfterViewInit() {
    console.log(this.child.whoAmI()); // I am a child component!
  }
}

При просмотре приложения в браузере отображается журнал консоли:

Output
I am a child component!

Родительскому компоненту удалось вызвать метод whoAmI дочернего компонента.

Заключение

Вы научились использовать ViewChild для доступа к директиве, дочернему компоненту и элементу DOM из класса родительского компонента.

Если шаблон динамически изменится на новый элемент, ViewChild автоматически обновит шаблон.

Если вам требуется доступ к нескольким дочерним элементам, вам следует использовать метод ViewChildren.

Если вы хотите узнать больше об Angular, посмотрите нашу страницу тем по Angular, где вы найдете упражнения и проекты по программированию.

Creative Commons License