модули - создать компонент angular




Как выбрать элемент в шаблоне компонента? (7)

Кто-нибудь знает, как получить элемент, определенный в шаблоне компонента? Полимер делает это действительно легко с $ и $$ .

Мне было просто интересно, как это сделать в Angular.

Возьмите пример из учебника:

import {Component} from '@angular/core'

@Component({
    selector:'display'
    template:`
     <input #myname(input)="updateName(myname.value)"/>
     <p>My name : {{myName}}</p>
    `

})
export class DisplayComponent {
    myName: string = "Aman";
    updateName(input: String) {
        this.myName = input;
    }
}

Как мне перехватить ссылку на элемент p или input из определения класса?


Вместо внедрения ElementRef и использования querySelector или чего-то подобного, вместо этого можно использовать декларативный способ прямого доступа к элементам в представлении:

<input #myname>
@ViewChild('myname') input; 

элемент

ngAfterViewInit() {
  console.log(this.input.nativeElement.value);
}

Пример StackBlitz

  • @ViewChild() поддерживает директиву или тип компонента в качестве параметра или имя (строку) переменной шаблона.
  • @ViewChildren() также поддерживает список имен в виде списка, разделенного запятыми (в настоящее время пробелы запрещены @ViewChildren('var1,var2,var3') ).
  • @ContentChild() и @ContentChildren() делают то же самое, но в облегченном DOM ( <ng-content> проецируемые элементы).

потомки

@ContentChildren() - единственный, который позволяет также запрашивать потомков

@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField; 

{descendants: true} должен быть по умолчанию, но не в 2.0.0 final, и это считается ошибкой
Это было исправлено в 2.0.1

читать

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

Например, ViewContainerRef который требуется динамически создаваемым компонентам вместо ElementRef по умолчанию

@ViewChild('myname', { read: ViewContainerRef }) target;

подписаться на изменения

Даже если дочерние элементы представления устанавливаются только при ngAfterViewInit() а дочерние элементы содержимого устанавливаются только при ngAfterContentInit() , если вы хотите подписаться на изменения результата запроса, это следует сделать в ngOnInit()

https://github.com/angular/angular/issues/9689#issuecomment-229247134

@ViewChildren(SomeType) viewChildren;
@ContentChildren(SomeType) contentChildren;

ngOnInit() {
  this.viewChildren.changes.subscribe(changes => console.log(changes));
  this.contentChildren.changes.subscribe(changes => console.log(changes));
}

прямой доступ к DOM

может запрашивать только элементы DOM, но не компоненты или экземпляры директив:

export class MyComponent {
  constructor(private elRef:ElementRef) {}
  ngAfterViewInit() {
    var div = this.elRef.nativeElement.querySelector('div');
    console.log(div);
  }

  // for transcluded content
  ngAfterContentInit() {
    var div = this.elRef.nativeElement.querySelector('div');
    console.log(div);
  }
}

получить произвольный проектируемый контент

См. Доступ к включенному контенту



Для людей, пытающихся получить экземпляр компонента внутри *ngIf или *ngSwitchCase , вы можете *ngSwitchCase этим трюком.

Создайте директиву init .

import {
    Directive,
    EventEmitter,
    Output,
    OnInit,
    ElementRef
} from '@angular/core';

@Directive({
    selector: '[init]'
})
export class InitDirective implements OnInit {
    constructor(private ref: ElementRef) {}

    @Output() init: EventEmitter<ElementRef> = new EventEmitter<ElementRef>();

    ngOnInit() {
        this.init.emit(this.ref);
    }
}

Экспортируйте свой компонент с именем, таким как myComponent

@Component({
    selector: 'wm-my-component',
    templateUrl: 'my-component.component.html',
    styleUrls: ['my-component.component.css'],
    exportAs: 'myComponent'
})
export class MyComponent { ... }

Используйте этот шаблон, чтобы получить экземпляр ElementRef AND MyComponent

<div [ngSwitch]="type">
    <wm-my-component
           #myComponent="myComponent"
           *ngSwitchCase="Type.MyType"
           (init)="init($event, myComponent)">
    </wm-my-component>
</div>

Используйте этот код в TypeScript

init(myComponentRef: ElementRef, myComponent: MyComponent) {
}

импортировать декоратор ViewChild из @angular/core следующим образом:

HTML-код:

<form #f="ngForm"> 
  ... 
  ... 
</form>

Код TS:

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

class TemplateFormComponent {

  @ViewChild('f') myForm: any;
    .
    .
    .
}

теперь вы можете использовать объект myForm для доступа к любому элементу в классе.

Source


Примечание : Это не относится к Angular 6 и выше, так как ElementRef стал ElementRef<T> с T обозначающим тип nativeElement .

Я хотел бы добавить, что если вы используете ElementRef , как рекомендовано всеми ответами, то вы сразу же столкнетесь с проблемой, что ElementRef имеет ужасное объявление типа, которое выглядит как

export declare class ElementRef {
  nativeElement: any;
}

это глупо в среде браузера, где nativeElement является HTMLElement .

Чтобы обойти это, вы можете использовать следующую технику

import {Inject, ElementRef as ErrorProneElementRef} from '@angular/core';

interface ElementRef {
  nativeElement: HTMLElement;
}

@Component({...}) export class MyComponent {
  constructor(@Inject(ErrorProneElementRef) readonly elementRef: ElementRef) { }
}

Angular 4+ : используйте renderer.selectRootElement с селектором CSS для доступа к элементу.

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

На данный момент часть ввода данных не разбита на компоненты, поэтому разделы управляются с помощью директив * ngIf. Мне нужно установить фокус на поле заметок проекта, если это существующий клиент, или поле имени, если они новые.

Я попробовал решения безуспешно. Тем не менее, обновление 3 в this ответе дало мне половину возможного решения. Другая половина пришла от ответа MatteoNY в this теме. Результат таков:

import { NgZone, Renderer } from '@angular/core';

constructor(private ngZone: NgZone, private renderer: Renderer) {}

setFocus(selector: string): void {
    this.ngZone.runOutsideAngular(() => {
        setTimeout(() => {
            this.renderer.selectRootElement(selector).focus();
        }, 0);
    });
}

submitEmail(email: string): void {
    // Verify existence of customer
    ...
    if (this.newCustomer) {
        this.setFocus('#firstname');
    } else {
        this.setFocus('#description');
    }
}

Поскольку единственное, что я делаю, это устанавливаю фокус на элементе, мне не нужно заниматься обнаружением изменений, поэтому я могу фактически запустить вызов renderer.selectRootElement за пределами Angular. Поскольку мне нужно дать время новым секциям на рендеринг, секция элемента обернута в тайм-аут, чтобы позволить потокам рендеринга наверстать упущенное перед попыткой выбора элемента. После того, как все это настроено, я могу просто вызвать элемент с помощью основных селекторов CSS.

Я знаю, что этот пример в основном касался события фокуса, но мне трудно, чтобы его нельзя было использовать в других контекстах.


 */
import {Component,ViewChild} from '@angular/core' /*Import View Child*/

@Component({
    selector:'display'
    template:`

     <input #myname (input) = "updateName(myname.value)"/>
     <p> My name : {{myName}}</p>

    `
})
export class DisplayComponent{
  @ViewChild('myname')inputTxt:ElementRef; /*create a view child*/

   myName: string;

    updateName: Function;
    constructor(){

        this.myName = "Aman";
        this.updateName = function(input: String){

            this.inputTxt.nativeElement.value=this.myName; 

            /*assign to it the value*/
        };
    }
}




angular-components