This is a classic. You have a parent and a child element. Child element is absolutely positioned and you want the user to scroll through its content. However, when you reach the bottom of the child element, the parent element (which also is allowed to have scroll bars) begins to scroll. That's undesirable. The basic behavior I want to reproduce is that of the comment section of the New York Times. For example:
The body is allowed to scroll down, but when you are at the bottom of the comment section, scrolling down doesn't do anything. I think the main difference in this case, is that I want to let the user scroll down when the cursor is positioned over the body element. Other approaches require to add a class to the body to prevent any scroll event in the body. I thought I would be able to do this with a bit of Javascript in Angular 2, but this is my failed attempt so far:
I have a custom directive in my child component:
<child-element scroller class="child"></child-element>
and this directive is supposed to stop the propagation of the scroll event to the body element:
import {Component} from 'angular2/core'
import {Directive, ElementRef, Renderer} from 'angular2/core';
@Directive({
selector: '[scroller]',
})
export class ScrollerDirective {
constructor(private elRef: ElementRef, private renderer: Renderer) {
renderer.listen(elRef.nativeElement, 'scroll', (event) => {
console.log('event!');
event.stopPropagation();
event.preventDefault();
})
}
}
It actually listens to the event but it doesn't stop the propagation.
Demo: Scroll down through the list of numbers and when you reach the bottom, its parent element starts to scroll down. That's the problem.
If you have another approach to accomplish this, please let me know.
UPDATE: Based on the answer provided by Günter Zöchbauer, I'm trying to prevent the wheel event when the user reaches the bottom. This is basically what I have so far in this updated demo:
renderer.listen(elRef.nativeElement, 'wheel', (e) => {
console.log('event', e);
console.log('scrollTop', elRef.nativeElement.scrollTop);
console.log('lastScrollTop', lastScrollTop);
if (elRef.nativeElement.scrollTop == lastScrollTop && e.deltaY > 0) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
else if (elRef.nativeElement.scrollTop == 0) {
lastScrollTop = -1;
}
else {
lastScrollTop = elRef.nativeElement.scrollTop;
}
}, false)
However, the logic is ugly and doesn't work great. For example, when the user reaches the bottom, scrolls up a little and scrolls down again, the parent component moves slightly. Does anyone know how to deal with this? A (much) better implementation?
UPDATE 2:
This is much better, but it is late now, so I will check again tomorrow.