Prevent scrolling of a child for distribution in Angular 2

This is a classic. You have parent and child elements. The child element is absolutely positioned, and you want the user to view its contents. However, when you reach the bottom of the child, the parent (which also has the ability to have scrollbars) starts to scroll. This is undesirable. The main behavior I want to reproduce is the comment section in The New York Times. For example :

enter image description here

The body is allowed to scroll down, but when you are at the bottom of the comment section, scrolling down does nothing. I think the main difference in this case is that I want the user to scroll down when the cursor is over the body element. Other approaches require adding a class to the body to prevent any scroll event in the body. I thought I could do this with a bit of Javascript in Angular 2, but this is my unsuccessful attempt:

enter image description here

I have a custom directive in my child component:

<child-element scroller class="child"></child-element>

and this directive should stop distributing 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 for the event, but does not stop the distribution.

Demo : Scroll down the list and when you reach the bottom, its parent starts scrolling down. This is problem.

If you have a different approach to achieving this, let me know.

thanks

UPDATE . Based on Günter Zöchbauer's answer, I try to prevent the wheel event when the user reaches the bottom. This is basically what I have 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 does not work perfectly. For example, when the user reaches the bottom, scrolls a little and scrolls again, the parent component moves a bit. Does anyone know how to deal with this? Is (much) better to implement?

UPDATE 2 :

This is much better, but it's already late, so tomorrow I will check again.

+5
source share
4 answers

I would suggest something more direct in my opinion: add an arbitrary class to an arbitrary parent and prevent scrolling through CSS overflow: hidden .

In this example, I wrote a directive to prevent the parent from scrolling while the element exists at all, as this was my desired behavior. Instead of OnDestroy and AfterViewInit for your use case, you should bind to mouseenter and mouseleave

HTML:

 <div add-class="noscroll" to="body">Some Content Here</div> 

CSS

 .noscroll { overflow: hidden; } 

TS:

 import {Directive, AfterViewInit, OnDestroy, Input} from "@angular/core"; @Directive({ selector: '[add-class]' }) export class AddClassDirective implements AfterViewInit, OnDestroy { @Input('add-class') className: string; @Input('to') selector: string; ngOnDestroy(): void { document.querySelector(this.selector).classList.remove(this.className); } ngAfterViewInit(): void { document.querySelector(this.selector).classList.add(this.className); } } 
+3
source

This is my best attempt.

 renderer.listen(elRef.nativeElement, 'wheel', (e) => { let el = elRef.nativeElement; let conditions = ((el.scrollTop + el.offsetHeight > el.scrollHeight)) && e.deltaY > 0 || el.scrollTop === 0 & e.deltaY < 0; if (conditions) { e = e || window.event; if (e.preventDefault) e.preventDefault(); e.returnValue = false; } }, false) 

Demo

It works great in Firefox, the stable and beta version of Chrome, but for some reason, Chrome dev behaves differently. If the user scrolls down heavily (or, equivalently, scrolls up), the parent moves a bit. Unfortunately, I noticed that the New York Times also has the same annoyance in the comment section. If you have any suggestions let me know.

I reported a problem that occurred in Chrome dev, and this was already the answer.

+2
source

I had a similar problem. I wanted to disable scrolling while my modal component was open.

Here's how I solved it:

 import { Component, HostListener } from '@angular/core'; @Component({ selector : 'app-modal', templateUrl: './modal.component.html', styleUrls : ['./modal.component.scss'], }) export class ModalComponent { @HostListener('wheel', ['$event']) handleWheelEvent(event) { event.preventDefault(); } ... 

I hope you find this helpful.

0
source

Source: https://habr.com/ru/post/1246658/


All Articles