有人知道如何获取组件模板中定义的元素吗?聚合物让$和$$变得很容易。

我只是想知道如何在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或输入元素的引用?


当前回答

从@angular/core中导入ViewChild装饰器,如下所示:

HTML代码:

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

TS代码:

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

class TemplateFormComponent {

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

现在你可以使用'myForm'对象来访问类中的任何元素。

其他回答

对于那些试图在*ngIf或*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和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) {
}

对于*ngIf中的组件,另一种方法是:

我想要选择的组件是在一个div的*ngIf语句中,@ jsgopil的答案上面可能工作(谢谢@ jsgopil !),但我最终找到了一种避免使用*ngIf的方法,通过使用CSS隐藏元素。

当[className]中的条件为真时,将显示div,使用#命名组件可以工作,并且可以从typescript代码中选择它。当条件为false时,它不会显示,而且我不需要选择它。

组件:

@Component({
    selector: 'bla',
    templateUrl: 'bla.component.html',
    styleUrls: ['bla.component.scss']
})
export class BlaComponent implements OnInit, OnDestroy {
    @ViewChild('myComponentWidget', {static: true}) public myComponentWidget: any;
    @Input('action') action: ActionType; // an enum defined in our code. (action could also be declared locally)

constructor() {
   etc;
}

// this lets you use an enum in the HMTL (ActionType.SomeType)
public get actionTypeEnum(): typeOf ActionType {
    return ActionType;
}

public someMethodXYZ: void {
    this.myComponentWidget.someMethod(); // use it like that, assuming the method exists
}

然后在bla。component.html文件中:

<div [className]="action === actionTypeEnum.SomeType ? 'show-it' : 'do-not-show'">

    <my-component #myComponentWidget etc></my-component>
</div>
<div>
    <button type="reset" class="bunch-of-classes" (click)="someMethodXYZ()">
        <span>XYZ</span>
    </button>
</div>   

和CSS文件:

 ::ng-deep {
    .show-it {
         display: block;   // example, actually a lot more css in our code
    }
    .do-not-show {
        display: none'; 
    }
}
 */
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*/
        };
    }
}

快速使用的最小示例:

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

@Component({
  selector: 'my-app',
  template:
  `
  <input #inputEl value="hithere">
  `,
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  @ViewChild('inputEl') inputEl:ElementRef; 

  ngAfterViewInit() {
    console.log(this.inputEl);
  }
}

在感兴趣的DOM元素上放置一个模板引用变量。在我们的例子中,这是<input>标签上的#inputEl。 在组件类中,通过@ViewChild装饰器注入DOM元素 访问ngAfterViewInit生命周期钩子中的元素。

注意:

如果你想操作DOM元素,请使用Renderer2 API而不是直接访问元素。允许直接访问DOM会使应用程序更容易受到XSS攻击

角4 +: 使用渲染器。使用CSS选择器来访问元素。

我有一个最初显示电子邮件输入的表单。输入电子邮件后,表单将被扩展,允许他们继续添加与他们的项目相关的信息。但是,如果他们不是现有的客户,表单将在项目信息部分上面包含一个地址部分。

到目前为止,数据输入部分还没有被分解成组件,所以这些部分是用*ngIf指令管理的。如果他们是现有客户,我需要将焦点设置在项目笔记字段,如果他们是新客户,则需要将焦点设置在名字字段。

我尝试了这些解决方案,但没有成功。然而,这个答案中的更新3给了我最终解决方案的一半。另一半来自MatteoNY的回复。结果是:

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的调用。在Angular外部选择trootelement。因为我需要给新部分时间来呈现,元素部分被包裹在一个超时中,以允许呈现线程在尝试元素选择之前有时间赶上。一旦所有这些设置,我可以简单地调用元素使用基本的CSS选择器。

我知道这个例子主要处理的是焦点事件,但是我很难理解这个例子不能用于其他上下文中。

更新:Angular在Angular 4中放弃了对Renderer的支持,并在Angular 9中完全删除了它。这个解决方案不应该受到迁移到Renderer2的影响。请参阅此链接以了解更多信息: Renderer迁移到Renderer2