有人知道如何获取组件模板中定义的元素吗?聚合物让$和$$变得很容易。
我只是想知道如何在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或输入元素的引用?
对于那些试图在*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) {
}
注意:这并不适用于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) { }
}
角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
对于那些试图在*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) {
}
快速使用的最小示例:
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攻击