I'm implementing a simple infinite-scroll directive in Angular2. I'm using @HostListener('window:scroll')
to get the scroll event and parsing the data from the $target
.
The question is, for every scroll event, everything will be checked once again with no need.
I checked the ionic infinite-scroll
directive for inspiration but they don't use @HostListener
, they need a more granular control, I guess.
I ended up on this issue while searching https://github.com/angular/angular/issues/13248 but couldn't find any way to do what I want.
I think if I create an Observable, subscribe to it with debounce and push (next) items to it, I will reach the behaviour I want, but I'm not being able to do that.
I would leverage debounce method decorator like:
export function debounce(delay: number = 300): MethodDecorator { return function (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) { const timeoutKey = Symbol(); const original = descriptor.value; descriptor.value = function (...args) { clearTimeout(this[timeoutKey]); this[timeoutKey] = setTimeout(() => original.apply(this, args), delay); }; return descriptor; }; }
and use it as follows:
@HostListener('window:scroll', ['$event']) @debounce() scroll(event) { ... }
Ng-run Example
I really like @yurzui's solution and I updated a lot of code to use it. However, I think it contains a bug. In the original code, there is only one timeout
per class but in practice one is needed per instance.
In Angular terms, this means that if the component in which @debounce()
is used is instantiated multiple times in a container, every instantiation will cancelTimeout
the previous instantiation and only the last will fire.
I propose this slight variant to eliminate this trouble:
export function debounce(delay: number = 300): MethodDecorator { return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { const original = descriptor.value; const key = `__timeout__${propertyKey}`; descriptor.value = function (...args) { clearTimeout(this[key]); this[key] = setTimeout(() => original.apply(this, args), delay); }; return descriptor; }; }
Of course, it is possible to be more sophisticated about disambiguating the synthetic __timeout__
property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With