Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(platform-browser): Expose
EventManagerPlugin
in the public api
This commit exposes the `EventManagerPlugin` abstract class to the public API. It provides a documentation with a usecase and a basic implementation describing the possibilities rationale for opening to the public API : 1. The `EVENT_MANAGER_PLUGINS` token is already public 2. The documentation provides a usecase 3. Plugins can already be implemented by following the same API 4. This does not increase the API surface because of 3.
- Loading branch information
Showing
17 changed files
with
201 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
load("//aio/content/examples:examples.bzl", "docs_example") | ||
|
||
package(default_visibility = ["//visibility:public"]) | ||
|
||
docs_example( | ||
name = "custom-events", | ||
) |
Empty file.
19 changes: 19 additions & 0 deletions
19
aio/content/examples/custom-events/src/app/app.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import {Component, HostListener} from '@angular/core'; | ||
import {ChildComponent} from './child.component'; | ||
|
||
@Component({ | ||
selector: 'app-root', | ||
standalone: true, | ||
imports: [ChildComponent], | ||
template: ` | ||
<app-child /> | ||
`, | ||
}) | ||
export class AppComponent { | ||
name = 'Angular'; | ||
|
||
@HostListener('click', ['$event']) | ||
onClick(event: Event) { | ||
console.log('click parent', event); | ||
} | ||
} |
16 changes: 16 additions & 0 deletions
16
aio/content/examples/custom-events/src/app/child.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {Component} from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'app-child', | ||
standalone: true, | ||
template: ` | ||
<button id="stoping" (click.stop)="onClick($event)">Propagation stopped</button> | ||
<br /> | ||
<button id="propagating" (click)="onClick($event)">Propagating...</button> | ||
`, | ||
}) | ||
export class ChildComponent { | ||
onClick(event: Event) { | ||
console.log('click child', event?.target); | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
aio/content/examples/custom-events/src/app/stop-event-plugin.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* eslint-disable @typescript-eslint/ban-types */ | ||
import {Injectable} from '@angular/core'; | ||
import {EventManagerPlugin} from '@angular/platform-browser'; | ||
|
||
@Injectable() | ||
export class StopEventPlugin extends EventManagerPlugin { | ||
// #docregion supports | ||
supports(event: string): boolean { | ||
return event.endsWith('.stop'); | ||
} | ||
// #enddocregion supports | ||
|
||
// #docregion addEventListener | ||
addEventListener(element: HTMLElement, eventName: string, handler: (event: Event) => void): Function { | ||
const eventWrapper = (event: Event) => { | ||
event.stopPropagation(); | ||
handler(event); | ||
}; | ||
|
||
// striping the stop modifier from the event name; | ||
const nonModifiedEventName = eventName.replace(/\.stop$/, ''); | ||
|
||
return this.manager.addEventListener(element, nonModifiedEventName, eventWrapper); | ||
} | ||
// #enddocregion addEventListener | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title>ContentProjection</title> | ||
<base href="/"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel="icon" type="image/x-icon" href="favicon.ico"> | ||
</head> | ||
<body> | ||
<app-root></app-root> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { bootstrapApplication } from '@angular/platform-browser-dynamic'; | ||
import { AppComponent } from './app/app.component'; | ||
import { EVENT_MANAGER_PLUGINS } from '@angular/platform-browser'; | ||
import { StopEventPlugin } from './app/stop-event-plugin'; | ||
|
||
|
||
bootstrapApplication(AppComponent, { | ||
// #docregion providers | ||
providers: [ | ||
{ provide: EVENT_MANAGER_PLUGINS, multi: true, useClass: StopEventPlugin} | ||
] | ||
// #enddocregion providers | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"description": "Custom Events", | ||
"files": [ | ||
"!**/*.d.ts", | ||
"!**/*.js", | ||
"!**/*.[1,2].*" | ||
], | ||
"file": "src/app/app.component.ts", | ||
"tags": ["Custom Events"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Custom Events Handeling | ||
|
||
Angular allows you to handle custom events, to extend existing ones or support new ones. | ||
|
||
## Handling user Events | ||
|
||
[Event Binding](/guide/event-binding) and the the `HostListener` decorator lets you listen for and respond to DOM events and components events. | ||
|
||
<code-example header="src/app/stop-event-plugin.ts" path="attribute-directives/src/app/highlight.directive.2.ts" region="mouse-methods"></code-example> | ||
|
||
<code-example language="html"> | ||
<navbutton (click)="onClick($event)">You can click me<nav/button> | ||
</code-example> | ||
|
||
## Event Handling by the EventManager | ||
|
||
Angular handles events using the `EventManager` service. It has a set of plugins that extend the `EventManagerPlugin` abstract class and delegates event subscription and handling to a plugin that supports particular events. | ||
|
||
Angular has a few built-in plugins such as one dedicated to [HammerJS](/api/platform-browser/HammerModule) events or the `KeyEventsPlugin` responsible for handling composite events such as `keydown.enter`. | ||
|
||
### `EventManagerPlugin` | ||
|
||
`EventManagerPlugin` is an abstract class with 2 methods to implement `supports` and `addEventListener`. | ||
|
||
Plugings are loaded using the `EVENT_MANAGER_PLUGINS` injection token and are provided to the `BrowserModule` using `multi: true`. | ||
|
||
For the `EventManager` to determine which plugin will handle the event, each plugin implements the `supports` method. | ||
The event manager will call `addEventListener` on the first plugin where `supports` returns `true`. | ||
|
||
## Handle a custom event | ||
|
||
Let's implement a plugin that will register events and call `Event.stopPropagation()` on them. | ||
This plugin will add the support for the `.stop` modifier and we'll be able to register events like `click.stop`. | ||
|
||
1. `support` needs to return `true` if the stop modifier is present : | ||
|
||
<code-example header="src/app/stop-event-plugin.ts (supports method)" path="custom-events/src/app/stop-event-plugin.ts" region="supports"></code-example> | ||
|
||
2. Wrap the event's handler to `stopPropagration` and register the wrapper. | ||
3. Extract the original event name and registrer the event with the manager. | ||
|
||
<code-example header="src/app/stop-event-plugin.ts (addEventListener method)" path="custom-events/src/app/stop-event-plugin.ts" region="addEventListener"></code-example> | ||
|
||
3. Add the plugin to the list of providers of the app. | ||
|
||
<code-example header="src/main.ts" path="custom-events/src/main.ts" region="providers"></code-example> | ||
|
||
|
||
You can now listen to the new custom events via [Event bindings](/guide/event-binding) or the `HostListener` decorator. | ||
|
||
<code-example language="html"> | ||
<navbutton (click.stop)="onClick($event)">Propagation stopped<nav/button> | ||
</code-example> | ||
|
||
|
||
|
||
Try this <live-example name="custom-events"></live-example>. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters