Hide angular button when scrolling down and show it again when scrolling up

Seeking a more efficient way to display a button only on up-scroll. My current implementation involves listening for every scroll-event, which seems like it might be too computationally intensive. If anyone has a better approach, I'm open to suggestions! The Requirement is: When the Page initially loads or on up-scroll the button should be displayed in the UI. On down-scroll the button should be hidden.

I utilized Angular's @HostListener(..) to monitor the scroll event.

Component

  public lastScrolledHeight: number = 0;
  public showAddButton: boolean = true;

  @HostListener('window:scroll', ['$event']) onScroll(event) {
    const window = event.path[1];
    const currentScrollHeight = window.scrollY;
    console.log(currentScrollHeight);

    if (currentScrollHeight > this.lastScrolledHeight) {
      this.showAddButton = false;
      console.log('should NOT show button');
    } else {
      this.showAddButton = true;
      console.log('should show button');
    }
    this.lastScrolledHeight = currentScrollHeight;
  }

HTML

  <button class="btn btn-success btn-circle btn-xl"
          [ngClass]="(showAddButton === true) ? 'scale-in' : 'scale-out'"
  </button>

Providing the CSS for completeness:

.scale-out {
  -webkit-animation: scale-out .2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
  animation: scale-out .2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}
.scale-in {
  -webkit-animation: scale-in .2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
  animation: scale-in .2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}

Open to any feedback. :)

Edit: Created a Stackblitz for Testing

Stackblitz

Answer №1

To optimize scroll events, consider converting them to Observables and using debounceTime for better control.

You have two options: either add a Subject to pass scroll information or create an Observable from the event itself.

scroll = new Subject<number>();
ngOnInit() {
  this.scroll
    .pipe(debounceTime(200))
    .subscribe((y) => this.dealWithScroll(window.scrollY));
}
ngOnDestroy() {
  this.scroll.complete();
}
@HostListener('window:scroll') watchScroll() {
  this.scroll.next(window.scrollY);
}
dealWithScroll(y: number) {}

Alternatively, you can create an Observable directly from the scroll event:

scroller: Subscription;
ngOnInit() {    
  this.scroller = fromEvent(window, 'scroll')
    .pipe(debounceTime(200))
    .subscribe(() => this.dealWithScroll(window.scrollY));      
}
ngOnDestroy() {
  this.scroller.unsubscribe();
}

Remember to avoid direct access to window object whenever possible. Additionally, simplify boolean checks like showAddButton === true to just showAddButton. And don't forget to unsubscribe/complete your Observables.

Answer №2

If I were to enhance the functionality, a slight buffer would be incorporated.

This addition would reduce the app's sensitivity to delicate touches and minimize the level of calculations required.

export class AppComponent {
  public lastScrolledHeight: number = 0;
  public showAddButton: boolean = true;
  private buffer = 0

  @HostListener('window:scroll', ['$event']) onScroll(event) {
    const window = event.path[1];

    if (this.ignoredByBuffer()) {
      return;
    }

    const currentScrollHeight = window.scrollY;

    if (currentScrollHeight > this.lastScrolledHeight) {
      this.showAddButton = false;
      console.log('should NOT show button');
    } else {
      this.showAddButton = true;
      console.log('should show button');
    }
    this.lastScrolledHeight = currentScrollHeight;
  }

  private ignoredByBuffer(): boolean {
    if (this.buffer < 10) {
      this.buffer += 1;
      return true;
    }
    this.buffer = 0;
    return false;
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Troubleshooting jQuery's issue with dynamically adding input fields

I came across a tutorial (which I tweaked slightly) on this website: code In JSFiddle, everything works perfectly fine with the code. However, when I implemented it on my actual page, it's not functioning as expected. I've been trying to trouble ...

What is the best way to adjust the dimensions of an image using CSS?

I've been struggling to adjust the dimensions of my image using CSS by specifying a width and height attribute. However, instead of resizing the picture, it seems to simply zoom in on the existing image. For instance, I have an image that is 90px by ...

Leveraging Ajax for establishing session and displaying outputs

Trying my best to make this work with AJAX, but it's a new concept for me. So bear with me as I figure this out... I've posted a couple of questions about resolving the issue at hand and we've made progress. However, a new challenge has pre ...

The function $http.get in AngularJS is providing an undefined response

In the process of developing a small Angular application, I started with this seed project: https://github.com/angular/angular-seed. The only modifications I made were to the following files: /app/view1/view1.js 'use strict'; angular.mod ...

Switching the color scheme between mobile and desktop devices to make the background look

As a newcomer to threejs, I have just begun learning and developing with this technology. I am aware that certain features may be different on mobile browsers compared to desktop ones due to limitations. However, I have encountered an issue that I cannot s ...

Creating a div with a scrollbar limited to a maximum of 100% of the page size

<!-- ********************************************************************************************************************************************************** RIGHT SIDEBAR CONTENT *********************************************************** ...

Utilize React to generate HTML content and send it as the email body through Node.js

I am currently working on a react application that consists of two main pages - AddStatus and ViewStatus. Both of these are implemented as react components. My current task involves sending out an email daily at a specific time, containing the details dis ...

Steps for making a "confirm" button within a modal that includes a redirect URL

I have developed a modal that, upon clicking on the confirm button, should redirect the user to the page titled securities-in-portfolio. modal <div class="modal-footer justify-content-center"> <button type="button" class ...

Typescript: Defining the correct return type for resolved parameters in promises

Exploring the world of TypeScript, I recently attempted to convert some basic JavaScript promise samples into TypeScript promises. While working on this conversion process, I encountered an issue that has left me puzzled and unable to find a solution even ...

Utilizing the power of JQuery and KineticJS in HTML5 for Drawing and Interactive Drag-and-Drop

Creating a page with mouse-drawn lines and drag-and-drop functionality has been challenging. The primary issue I'm facing is the inability to delete more than one item. Additionally, cloning an item on drag does not work as intended, resulting in dup ...

A method for reversing specific characters within lengthy strings

I'm currently tackling a coding problem: For a given string s and an integer k, the task is to reverse the first k characters for every 2k characters starting from the beginning of the string. If there are less than k characters remaining, reverse al ...

When double quotes are used in a string within an HTML input field, they may display as &

Using PHP, I am retrieving data from an SQL database and generating JavaScript code to create an edit button for each entry. The edit button triggers a text input field within a form. When the user clicks on the generated edit button, the text in this inpu ...

Is there a way to securely store my JWT Token within my application's state?

userAction.js -> Frontend, Action export const login = (userID, password) => async (dispatch) => { try { dispatch({ type: USER_LOGIN_REQUEST }); const url = "http://localhost:8080/authenticate/"; const ...

Allow specific HTML tags to be unescaped in Vue.js

Utilizing the v-html method to unescape HTML tags, I am seeking a way to only unescape the <a></a> tags within a string. To illustrate this: Input: <p> Hello World </p> <a target="_blank" href="https://www.google. ...

Modify the `value` of the `<input type=color>` element

Hello there! I have been working on a feature where I need users to select a color and have that choice reflected in the value field. Initially, I assumed this could be achieved easily through Bootstrap's features since my project is based on Bootstr ...

What is the best way to empty the input field after a download event is completed in Node.JS?

For hours on end, I've been struggling with a persistent issue in my video downloader app. After successfully downloading a video, the input field where the URL is entered remains filled instead of clearing out. The screenshot below illustrates the p ...

Angular.js - organizing a list of items and preserving the outcome

Here is a compilation of randomly arranged items: <ul class="one" drag-drop="page.items"> <li ng-repeat='item in page.items|orderBy:page.random as result'> <img ng-src="http://placecage.com/{{item.id*100}}/{{item.id*100}}"& ...

Adhering to a modular approach to design

I am facing an issue with two modules: One is the .master-header and the other is the .header-nav The .header-nav is contained within the .master-header and consists of a simple navigation menu: <nav class="header-nav"> <ul> ...

Having difficulty encapsulating three.js rendered particles within a single div

I'm facing an issue where the particles generated by my three.js project are not contained within a specific div or html element as intended. Instead of staying within the designated boundaries, the particles are spreading across the entire DOM witho ...

How come Font-face isn't functioning properly on Internet Explorer 11?

I have designed a new website at , however, I am facing issues with my CSS on Internet Explorer 11 (version 11.608.15063.0). The font-face and dropdown menu are not displaying correctly. Can anyone assist me with this problem? ...