有人知道如何获取组件模板中定义的元素吗?使用$
和$$
我只是想知道如何在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
元素的引用?
答案 0 :(得分:775)
不是从那里注入ElementRef
并使用querySelector
或类似的,而是可以使用声明方式来直接访问视图中的元素:
<input #myname>
@ViewChild('myname') input;
元素
ngAfterViewInit() {
console.log(this.input.nativeElement.value);
}
@ViewChildren('var1,var2,var3')
)。 <ng-content>
投影元素中)。<强>后代强>
@ContentChildren()
是唯一允许查询后代
@ContentChildren(SomeTypeOrVarName, {descendants: true}) someField;
<击>
{descendants: true}
应该是默认值,但不是2.0.0最终版本considered a bug
击>
这在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);
}
}
获取任意预计内容
答案 1 :(得分:185)
您可以通过将ElementRef
注入到元素的构造函数中来获取DOM元素的句柄:
constructor(myElement: ElementRef) { ... }
文档:https://angular.io/docs/ts/latest/api/core/index/ElementRef-class.html
答案 2 :(得分:46)
import { Component, ElementRef, OnInit } from '@angular/core';
@Component({
selector:'display',
template:`
<input (input)="updateName($event.target.value)">
<p> My name : {{ myName }}</p>
`
})
class DisplayComponent implements OnInit {
constructor(public element: ElementRef) {
this.element.nativeElement // <- your direct element reference
}
ngOnInit() {
var el = this.element.nativeElement;
console.log(el);
}
updateName(value) {
// ...
}
}
已更新示例以使用最新版本
有关原生元素的更多详情,here
答案 3 :(得分:17)
Angular 4 + :
使用renderer.selectRootElement
和CSS选择器来访问元素。
我有一张最初显示电子邮件输入的表单。输入电子邮件后,表格将被扩展,以允许他们继续添加与其项目相关的信息。但是,如果他们不现有客户,则表单将包含项目信息部分上方的地址部分。
截至目前,数据输入部分尚未分解为组件,因此这些部分使用* ngIf指令进行管理。如果它们是现有客户端,我需要将焦点放在项目备注字段上,如果它们是新的,则需要将焦点放在第一个名称字段上。
我尝试了解决方案但没有成功。但是,this回答中的更新3给了我最终解决方案的一半。另一半来自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
之外。角。因为我需要给新部分渲染时间,所以元素部分被包装在超时中以允许渲染线程在尝试元素选择之前赶上时间。完成所有设置之后,我可以使用基本的CSS选择器简单地调用元素。
我知道这个例子主要涉及焦点事件,但对我来说这很难在其他情况下使用。
答案 4 :(得分:12)
对于尝试抓取*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) {
}
答案 5 :(得分:8)
*/
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*/
};
}
}
答案 6 :(得分:8)
从@ angular / core导入ViewChild装饰器,如下所示:
<form #f="ngForm"> ... </form>
import { ViewChild } from '@angular/core';
class TemplateFormComponent {
@ViewChild('f') myForm: any;
.
.
.
}
现在你可以使用'myForm'对象来访问类中的任何元素。
源: https://codecraft.tv/courses/angular/forms/template-driven/
答案 7 :(得分:3)
我想补充一点,如果你按照所有答案的建议使用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) { }
}
答案 8 :(得分:3)
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);
}
}
#inputEl
标记上的<input>
。ngAfterViewInit
生命周期挂钩中的元素。注意:
如果要操作DOM元素,请使用Renderer2 API而不是直接访问元素。允许直接访问DOM可以使您的应用程序更容易受到XSS攻击
答案 9 :(得分:1)
立即获得下一个兄弟,请使用此
event.source._elementRef.nativeElement.nextElementSibling
答案 10 :(得分:1)
我有两种方式:
第一种方式:
您可以通过将 ElementRef 注入到组件的构造函数中来获取 DOM 元素的句柄:
constructor(private myElement: ElementRef) {
this.myElement.nativeElement // <- your direct element reference
}
第二种方式:
@Component({
selector: 'my-app',
template:
`
<input #input value="enterThere">
`,
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
@ViewChild('input') input:ElementRef;
ngAfterViewInit() {
console.log(this.input);
}
答案 11 :(得分:0)
如果您使用的是Angular Material,则可以利用cdkFocusInitial指令。
示例:<input matInput cdkFocusInitial>
在此处了解更多信息: https://material.angular.io/cdk/a11y/overview#regions
答案 12 :(得分:0)
对于*ngIf
内部的组件,另一种方法:
我想要选择的组件位于div的* ngIf语句中,上面的@jsgoupil的答案可能有效(谢谢@jsgoupil!),但最终我找到了一种避免使用* ngIf的方法,即通过使用CSS隐藏元素。
当[className]中的条件为true时,将显示div,并使用#works命名组件,并且可以从打字稿代码中进行选择。如果条件为假,则不显示它,而且我也不需要选择它。
组件:
@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';
}
}