An output property lets an Angular directive or component expose a custom event to its parent template. Declare it with @Output and connect it to an EventEmitter; calling emit sends a value to listeners. The emitted value may be a string, number, data-model object, or JavaScript Event object. section 14.4 section 16.5
Use an output property to:
- Translate a host DOM event into an application-specific event, such as emitting a product category after a row is clicked. section 14.4
- Choose the template-facing event name with the @Output alias and pass the payload through emit(value). section 14.4
- Pair an input property with a change event to create a two-way binding, including the [(paModel)] shorthand. section 14.6
- Test emitted values by subscribing to the EventEmitter and triggering the originating interaction directly or through host events. section 29.4.5
Directive event and template listener
A directive can expose @Output("pa-category") click = new EventEmitter<string>();. After its host click, it calls this.click.emit(this.product.category). A parent template listens with (pa-category)="newProduct.category = $event", receiving the emitted category as $event.
Output-driven two-way binding
The PaModel directive emits a new input value from @HostListener("input", ["$event.target.value"]). Its @Output("paModelChange") update = new EventEmitter<string>() sends the value, allowing [paModel] and (paModelChange) to collapse into [(paModel)].
Listing 14.15. Defining an output property in the attr.directive.ts file in the src/app folder
import { Directive, ElementRef, Input, SimpleChanges, Output, EventEmitter }
from "@angular/core";
import { Product } from "./product.model";
@Directive({
selector: "[pa-attr]"
})
export class PaAttrDirective {
constructor(private element: ElementRef) {
this.element.nativeElement.addEventListener("click", () => {
if (this.product != null) {
this.click.emit(this.product.category);
}
});
}
@Input("pa-attr")
bgClass: string | null = "";
@Input({ required: true, alias: "fg-class"})
fgClass: string | undefined;
@Input("pa-product")
product: Product = new Product();
@Output("pa-category")
click = new EventEmitter<string>();
ngOnChanges(changes: SimpleChanges) {
["bgClass", "fgClass"].forEach(c => {
let change = changes[c];
if (change) {
let classList = this.element.nativeElement.classList;
if (!change.isFirstChange() &&
classList.contains(change.previousValue)) {
classList.remove(change.previousValue);
}
if (!classList.contains(change.currentValue)) {
classList.add(change.currentValue);
}
}
});
}
}
Inspect the complete directive listing to see imports, input properties, the aliased output property, host-event handling, and emitted payload together. section 14.4
