将事件从指令发送到父元素
Emit event from Directive to parent element
我在 Angular 2 应用程序的 HTML 模板中有一个元素。我给它添加了一个指令:
<div myCustomDirective>HELLO</div>
我希望每当我将鼠标悬停在 div
上时,div
中的文本都应该更改,但这需要在 Directive
(mouseover)
事件中完成。
如何从 Directive
发出事件并将其捕获到父元素中?
如果myCustomDirective
有一个输出@Output() someEvent:EventEmitter = new EventEmitter();
那么你可以使用
<div myCustomDirective (someEvent)="callSomethingOnParent($event)">HELLO</div>
我想在@GünterZöchbauer 的回答中补充一点,如果您尝试从 structural 指令发出事件并使用星号 (*
)应用指令时的语法,它将不起作用。 Angular 5.2.6 仍然不支持 @Output
绑定结构指令如果与 *
语法一起使用(参见 GitHub issue)。
您必须将其转换为 de-sugarized 形式 (see here),即:
<ng-template [customDirective]="foo" (customDirectiveEvent)="handler($event)">
<div class="name">{{hero.name}}</div>
</ng-template>
而不是:
<div *customDirective="foo" (customDirectiveEvent)="handler($event)" class="name">{{hero.name}}</div>
这是我使用 Angular13 的解决方案。我打算创建一个分页组件,因此请忽略名称。
指令:
import {Directive, EventEmitter, Input, OnInit, Output, TemplateRef, ViewContainerRef} from '@angular/core';
@Directive({
selector: '[appPaginate]'
})
export class PaginateDirective implements OnInit {
@Output() newItemEvent: EventEmitter<string> = new EventEmitter<string>()
constructor( private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
ngOnInit() {
}
@Input() set appPaginate(condition: any) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.newItemEvent.emit('Directive working')
}
}
}
Component.html:
<ng-template [appPaginate]="condition" (newItemEvent)="update($event)">
<p>{{valueFromDirective}}</p>
</ng-template>
Component.ts
import {Component, Input, OnInit} from '@angular/core';
import {Item} from "./item";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'tutorial';
condition = true;
valueFromDirective = this.title;
ngOnInit() {
}
update($event: any) {
this.valueFromDirective = $event;
}
}
解释
基于@Alexander 和@Zochbauer 的讨论。使用 <ng-template>
,您可以定义只由 Angular 渲染的模板内容,当您直接或间接地特别指示它这样做时,允许您完全控制内容的方式和时间被展示。因此,当满足您的条件时,您将需要使用此行将发出的值显示到 html:
this.viewContainer.createEmbeddedView(this.templateRef);
N.B。这只是为了帮助那些认为事件发射器在 Angular 7+.
上不起作用的人
您也可以使用与指令相同的名称 @Output
:
@Directive({
selector: '[myCustomMouseover]'
})
export class MyCustomMouseoverDirective {
@Output()
public myCustomMouseover = new EventEmitter<void>();
@HostListener('mouseover', ['$event'])
public onMouseover(event: MouseEvent): void {
if (/* only trigger in certain conditions */) {
this.myCustomMouseover.emit();
}
}
}
您可以在任何元素中使用,例如:
<div (myCustomMouseover)="handler()">
...
</div>
我在 Angular 2 应用程序的 HTML 模板中有一个元素。我给它添加了一个指令:
<div myCustomDirective>HELLO</div>
我希望每当我将鼠标悬停在 div
上时,div
中的文本都应该更改,但这需要在 Directive
(mouseover)
事件中完成。
如何从 Directive
发出事件并将其捕获到父元素中?
如果myCustomDirective
有一个输出@Output() someEvent:EventEmitter = new EventEmitter();
那么你可以使用
<div myCustomDirective (someEvent)="callSomethingOnParent($event)">HELLO</div>
我想在@GünterZöchbauer 的回答中补充一点,如果您尝试从 structural 指令发出事件并使用星号 (*
)应用指令时的语法,它将不起作用。 Angular 5.2.6 仍然不支持 @Output
绑定结构指令如果与 *
语法一起使用(参见 GitHub issue)。
您必须将其转换为 de-sugarized 形式 (see here),即:
<ng-template [customDirective]="foo" (customDirectiveEvent)="handler($event)">
<div class="name">{{hero.name}}</div>
</ng-template>
而不是:
<div *customDirective="foo" (customDirectiveEvent)="handler($event)" class="name">{{hero.name}}</div>
这是我使用 Angular13 的解决方案。我打算创建一个分页组件,因此请忽略名称。
指令:
import {Directive, EventEmitter, Input, OnInit, Output, TemplateRef, ViewContainerRef} from '@angular/core';
@Directive({
selector: '[appPaginate]'
})
export class PaginateDirective implements OnInit {
@Output() newItemEvent: EventEmitter<string> = new EventEmitter<string>()
constructor( private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }
ngOnInit() {
}
@Input() set appPaginate(condition: any) {
if (condition) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.newItemEvent.emit('Directive working')
}
}
}
Component.html:
<ng-template [appPaginate]="condition" (newItemEvent)="update($event)">
<p>{{valueFromDirective}}</p>
</ng-template>
Component.ts
import {Component, Input, OnInit} from '@angular/core';
import {Item} from "./item";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'tutorial';
condition = true;
valueFromDirective = this.title;
ngOnInit() {
}
update($event: any) {
this.valueFromDirective = $event;
}
}
解释
基于@Alexander 和@Zochbauer 的讨论。使用 <ng-template>
,您可以定义只由 Angular 渲染的模板内容,当您直接或间接地特别指示它这样做时,允许您完全控制内容的方式和时间被展示。因此,当满足您的条件时,您将需要使用此行将发出的值显示到 html:
this.viewContainer.createEmbeddedView(this.templateRef);
N.B。这只是为了帮助那些认为事件发射器在 Angular 7+.
上不起作用的人您也可以使用与指令相同的名称 @Output
:
@Directive({
selector: '[myCustomMouseover]'
})
export class MyCustomMouseoverDirective {
@Output()
public myCustomMouseover = new EventEmitter<void>();
@HostListener('mouseover', ['$event'])
public onMouseover(event: MouseEvent): void {
if (/* only trigger in certain conditions */) {
this.myCustomMouseover.emit();
}
}
}
您可以在任何元素中使用,例如:
<div (myCustomMouseover)="handler()">
...
</div>