ذات مرة ، كتبت مقالة حول العمل مع EventManager في Angular . في ذلك ، تحدثت عن كيفية حفظ البنية المعتادة لاشتراكات الأحداث ، مع تجنب المحفزات غير الضرورية للتحقق من التغييرات على الأحداث المتكررة والحساسة.
ومع ذلك ، فإن الطريقة التي وصفتها مرهقة ويصعب فهمها. حان الوقت لإعادة كتابة الترشيح على الديكور.

إعادة موجزة
بالنسبة لأولئك الذين لم يقرؤوا ولا يريدون قراءة المقالة السابقة ، ملخص المشكلة:
- يسمح Angular بالاشتراك التعريفي في الأحداث في القالب (
(eventName)
) ومن خلال الديكور ( @HostListener(‘eventName’)
). - باستخدام إستراتيجية التحقق من التغيير ،
OnPush
ستقوم Angular بإجراء فحص في حالة وقوع حدث اشتركنا فيه بهذه الطريقة. - أحداث مثل
scroll
، mousemove
، drag
أثار في كثير من الأحيان. في الممارسة العملية ، ما عليك سوى الرد على بعضها (على سبيل المثال ، عندما قام المستخدم بتمرير الحاوية حتى النهاية - قم بتحميل عناصر جديدة). - يعالج الزاوي معالجة الأحداث
EventManager
باستخدام EventManagerPlugin
s المقدمة . - Angular , .
. . .
Angular (keydown.ctrl.enter
).
, EventManager
. . Angular , EVENT_MANAGER_PLUGINS
. , , . addEventListener
, , , , , . .
preventDefault
stopPropagation
. , , , :
@Injectable()
export class StopEventPlugin {
supports(event: string): boolean {
return event.split('.').includes('stop');
}
addEventListener(
element: HTMLElement,
event: string,
handler: Function
): Function {
const wrapped = (event: Event) => {
event.stopPropagation();
handler(event);
};
return this.manager.addEventListener(
element,
event
.split('.')
.filter(v => v !== 'stop')
.join('.'),
wrapped,
);
}
}
. , :
- Angular, .
- .
- .
, NgZone
:
@Injectable()
export class SilentEventPlugin {
supports(event: string): boolean {
return event.split('.').includes('silent');
}
addEventListener(
element: HTMLElement,
event: string,
handler: Function
): Function {
return this.manager.getZone().runOutsideAngular(() =>
this.manager.addEventListener(
element,
event
.split('.')
.filter(v => v !== 'silent')
.join('.'),
handler,
),
);
}
}
, .
, -. /, this
.
, , . — - , , . $event
@HostListener
. :
export function shouldCall<T>(
predicate: Predicate<T>
): MethodDecorator {
return (_target, _key, desc: PropertyDescriptor) => {
const {value} = desc;
desc.value = function(this: T, ...args: any[]) {
if (predicate.apply(this, args)) {
value.apply(this, args);
}
};
};
}
. — - Angular, .
Angular 10 Ivy , markDirty(this)
. , - NgZone
. . , . , NgZone
, :
@Injectable()
export class ZoneEventPlugin {
supports(event: string): boolean {
return event.split('.').includes('init');
}
addEventListener(
_element: HTMLElement,
_event: string,
handler: Function
): Function {
const zone = this.manager.getZone();
const subscription = zone.onStable.subscribe(() => {
subscription.unsubscribe();
handler(zone);
});
return () => {};
}
}
— .init
, ( , ). @HostListener(‘prop.init’, [‘$event’])
:
export function shouldCall<T>(
predicate: Predicate<T>
): MethodDecorator {
return (_, key, desc: PropertyDescriptor) => {
const {value} = desc;
desc.value = function() {
const zone = arguments[0] as NgZone;
Object.defineProperty(this, key, {
value(this: T, ...args: any[]) {
if (predicate.apply(this, args)) {
zone.run(() => {
value.apply(this, args);
});
}
},
});
};
};
}
, . , . Ivy.

, , :
https://stackblitz.com/edit/angular-event-filter-decorator
, , , . , , . async
Observable
:
<p *ngFor="let item of service.items$ | async">{{item}}</p>
, :
export function scrolledToBottom(
{scrollTop, scrollHeight, clientHeight}: HTMLElement
): boolean {
return scrollTop >= scrollHeight - clientHeight - 20;
}
@Component({
selector: 'awesome-component',
templateUrl: './awesome-component.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AwesomeComponent {
constructor(@Inject(Service) readonly service: Service) {}
@HostListener('scroll.silent', ['$event.currentTarget'])
@HostListener('init.onScroll', ['$event'])
@shouldCall(scrolledToBottom)
onScroll() {
this.service.loadMore();
}
}
. :
https://stackblitz.com/edit/angular-event-filters-scroll
, . CustomEvent
, . .
(1 gzip) open-source- @tinkoff/ng-event-filters
. Angular 10 2.0.0, markDirty(this)
, Angular 4.
npm-
-, open source, ? Angular Open-source Library Starter, . CI, , , CHANGELOG, .