Angular Event Modifier
Tags: angular, typescript, frontend
Published: 2024-04-21 09:38:01

---
title: Angular Event Modifier
published: true
description: 
tags: angular,typescript,frontend
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
# published_at: 2024-04-21 09:36 +0000
---

## Source Code
- version `17.3.5`
- commit `cc57d4c4998b4e38f940afdf358af37185028072`

## EventManagerPlugin
- For the official, it does provide an event management solution that allows for different monitoring based on any event name
- However, it is only based on the event name to listen to DOM elements and handle their listening

## The official does not provide a solution for processing component outputs
- According to [source code](https://github.com/angular/angular/blob/17.3.5/packages/core/src/render3/instructions/listener.ts#L212) We know that the `outputs` of all components are actually subscribed directly, which means there is no chance to intercept them

## Is the component output actually being monitored twice?
- As mentioned above, all components are subscribed directly. However, when a component is subscribed directly, it also performs event listening, which means that `EventManagerPlugin` can also listen. After all, custom components are also DOM elements
- But here's the problem. Even if you can handle this listening by creating an event manager, it only handles event listening, and subscriptions have nothing to do with it. In normal development, you will never call the DOM element of a component to do a `dispatchEvent`
- Another issue is that the event manager relies on [source code](https://github.com/angular/angular/blob/17.3.5/packages/platform-browser/src/dom/events/event_manager.ts#L108),`addEventListener` interface obtains an element and event name. How to find the corresponding component through the element?

## Magic modification moment, showcasing skills begins
- We found that there is an attribute called `__ngContext__` on the element, and the number on this attribute is actually the LView ID
- We use publicly available and non-public methods `ɵgetLContext` Get its LContext. Then read it to LView
- On LView, there are many key attributes, and component instances are one of them [Index position](https://github.com/angular/angular/blob/17.3.5/packages/core/src/render3/interfaces/view.ts#L185)
- Once we find the corresponding element of the component, we can hook up the original event emission and let it only go through our own listening channel. This part is relatively simple, just look at the [source code](https://github.com/wszgrcy/cyia-ngx-common/blob/master/lib/src/event/event.service.ts#L109-L121)

## Handling event modifiers
- There are two types of event modifiers, one is `guard` that returns true to prohibit, and the other is `map`, which is used for converting data
- The code comes with some 'guard' type modifiers. From [Vue source code](https://github.com/vuejs/core/blob/v3.4.23/packages/runtime-dom/src/directives/vOn.ts#L14)
- Regarding keyboard type event modifiers, fully call the official ng `ɵKeyEventsPlugin`

## Use
- [source code](https://github.com/wszgrcy/cyia-ngx-common/blob/master/lib/src/event/event.service.ts)
- `npm i @cyia/ngx-common`

```ts
// app module
import { EVENT_MODIFIER_OPTIONS, EventModifiersPlugin } from '@cyia/ngx-common/event';

  providers: [
    {
      provide: EVENT_MANAGER_PLUGINS,
      useClass: EventModifiersPlugin,
      multi: true,
      deps: [DOCUMENT],
    },
    {
      provide: EVENT_MODIFIER_OPTIONS,
      useValue: {
        modifiers: {
          map: {
            // custom event modifier
            prefix: (value) => {
              return `prefix:${value}`;
            },
          },
        },
        componentOutput: true,
      },
    },
  ],
```

```html
<div (click)="clicked('divClicked')">
  <button (click.stop.once)="clicked('btnClicked')">点击</button>
</div>
<app-a (output2.prefix.once)="output($event)" (output2)="output($event)"></app-a>
```

## Contact me
- If you have any technical issues, please  contact me for assistance `wszgrcy@gmail.com`