рдПрдХ рдмрд╛рд░, рдореИрдВрдиреЗ рдПрдВрдЧреБрд▓рд░ рдореЗрдВ EventManager рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд▓реЗрдЦ рд▓рд┐рдЦрд╛ ред рдЗрд╕рдореЗрдВ, рдореИрдВрдиреЗ рдЗрд╕ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХреА рдХрд┐ рдХреИрд╕реЗ рдЖрдк рдИрд╡реЗрдВрдЯ рд╕рджрд╕реНрдпрддрд╛ рдХреЗ рд▓рд┐рдП рд╕рд╛рдорд╛рдиреНрдп рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕ рдХреЛ рдмрдЪрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рдЬрдмрдХрд┐ рдЕрдХреНрд╕рд░ рдФрд░ рд╕рдВрд╡реЗрджрдирд╢реАрд▓ рдШрдЯрдирд╛рдУрдВ рдкрд░ рдкрд░рд┐рд╡рд░реНрддрдиреЛрдВ рдХреА рдЬрд╛рдБрдЪ рдХреЗ рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЯреНрд░рд┐рдЧрд░ рд╕реЗ рдмрдЪрддреЗ рд╣реИрдВред
рд╣рд╛рд▓рд╛рдБрдХрд┐, рдореИрдВрдиреЗ рдЬрд┐рд╕ рд╡рд┐рдзрд┐ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рд╣реИ рд╡рд╣ рдмреЛрдЭрд┐рд▓ рдФрд░ рд╕рдордЭрдиреЗ рдореЗрдВ рдХрдард┐рди рд╣реИред рдпрд╣ рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдкрд░ рдлрд╝рд┐рд▓реНрдЯрд░рд┐рдВрдЧ рдХреЛ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдиреЗ рдХрд╛ рд╕рдордп рд╣реИред

рд╕рдВрдХреНрд╖рд┐рдкреНрдд рд░рд┐рдкреНрд▓реЗ
рдЙрди рд▓реЛрдЧреЛрдВ рдХреЗ рд▓рд┐рдП рдЬреЛ рдкрд┐рдЫрд▓реЗ рд▓реЗрдЦ рдХреЛ рдирд╣реАрдВ рдкрдврд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рд░рд╛рдВрд╢:
- рдХреЛрдгреАрдп рдЯреЗрдореНрдкрд▓реЗрдЯ (
(eventName)
) рдФрд░ рд╕рдЬреНрдЬрд╛рдХрд╛рд░реЛрдВ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ ( ) рдореЗрдВ рдШрдЯрдирд╛рдУрдВ рдХреА рдШреЛрд╖рдгрд╛ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ @HostListener(тАШeventNameтАЩ)
ред - рдПрдХ рдкрд░рд┐рд╡рд░реНрддрди рд╕рддреНрдпрд╛рдкрди рд░рдгрдиреАрддрд┐ рдХреЗ рд╕рд╛рде,
OnPush
рдпрджрд┐ рдХреЛрдИ рдШрдЯрдирд╛ рдШрдЯрддреА рд╣реИ, рддреЛ рдПрдВрдЧреБрд▓рд░ рдПрдХ рдорд╛рдиреНрдпрддрд╛ рдЪрд▓рд╛рдПрдЧрд╛ред - рдЬреИрд╕реЗ рдШрдЯрдирд╛рдХреНрд░рдо
scroll
, mousemove
, drag
рдмрд╣реБрдд рдмрд╛рд░ рд╢реБрд░реВ рд╣реЛ рдЧрдпрд╛ред рд╡реНрдпрд╡рд╣рд╛рд░ рдореЗрдВ, рдЖрдкрдХреЛ рдХреЗрд╡рд▓ рдЙрдирдореЗрдВ рд╕реЗ рдХреБрдЫ рдХрд╛ рдЬрд╡рд╛рдм рджреЗрдирд╛ рд╣реЛрдЧрд╛ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдХрдВрдЯреЗрдирд░ рдХреЛ рдЕрдВрдд рддрдХ рд╕реНрдХреНрд░реЙрд▓ рдХрд┐рдпрд╛ рдерд╛ - рдирдП рддрддреНрд╡ рд▓реЛрдб рдХрд░реЗрдВ)ред EventManager
рдкреНрд░рджрд╛рди рдХрд┐рдП рдЧрдП EventManagerPlugin
рдПрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХреЛрдгреАрдп рдШрдЯрдирд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╕рдВрднрд╛рд▓рддрд╛ рд╣реИ ред- 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, .