What is the best way to ensure that the scroll position on each page in shinydashboard remains unaffected by changes in the scroll position on other pages?

When navigating between pages A and B in my shinydashboard app, I noticed that the scroll position of one page affects the scroll position of the other. How do I make the scrolls independent?

To illustrate my issue, I've included a stable shinydashboard app inside shinyGallery:

Even with some CSS and JS code added to my app, I couldn't achieve independent scrolling for each page within the app.

It seems that all shinydashboards exhibit this behavior...

Ideally, I want each page to maintain its scroll position, regardless of how many pages I navigate through.

EDIT

library(shiny)
library(shinydashboard)

header <- dashboardHeader(title = "Dashboard", titleWidth = 320)

sidebar <- dashboardSidebar(
width = 320,

sidebarMenu(
menuItem(
  text = "A1", 
  tabName = "st1"
),
menuItem(
  text = "A2",
  menuSubItem(
    text = "AA1",
    tabName = "nd2"
  ),
  menuSubItem(
    text = "AA2", 
    tabName = "rd3"
  ), 
  menuSubItem(
    text = "AA3", 
    tabName = "th4"
  )
)
)
)

body <- dashboardBody(

HTML(
"<head>
<style>
.small-box {
height: 500px;
}
</style>
</head>"
),

tabItems(

tabItem(
  tabName = "st1", 

  fluidPage(
    column(
      width = 6, 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow")
    )
  )
), 

tabItem(
  tabName = "nd2", 

  fluidPage(
    column(
      width = 6, 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow")
    )
  )
), 

tabItem(
  tabName = "rd3", 

  fluidPage(
    column(
      width = 6, 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow")
    )
  )
), 

tabItem(
  tabName = "th4", 

  fluidPage(
    column(
      width = 6, 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow"), 
      valueBox(value = 500, subtitle = "stack overflow")
    )
  )
)

)



ui <- dashboardPage(header = header, sidebar, body)

server <- function(input, output) {
  
}

shinyApp(ui, server)

App link.

Answer №1

This unique script is designed to monitor and remember the scroll position of each menuitem ("page") and restore the scroll position when returning to a previously visited page.

You can watch a demonstration of this script in action by clicking on the following video link:

// CSS selector that identifies menu items to track, excluding treeview/expandbutton
var menuItemsSelector = "ul.sidebar-menu li:not(.treeview)";

// Set a delay (ms) before restoring scroll position to allow page content to load
var delayBeforeRestoringPosition = 50;

// ### ### ### ### ###

// Override console.log to filter out unwanted messages
// Only messages starting with "*" will be displayed - e.g., "*Hello" will print as "Hello"
consolelog = console.log;
console.log = function(message) { if (message.indexOf("*") == 0) consolelog(message.substring(1)); }

// Array to store menuitem positions
var arrMenuPosition = [];

// Flag to track scrolling status
var isScrolling = false;

// Variable to hold the current/active menuitem for saving scroll position
var currentMenuItem = null;

// Function to retrieve text of the current menu item
var getCurrentMenuItemText = () => { return currentMenuItem.textContent.trim(); }

// Function to handle scroll actions (save and restore)
var scrollHandler = (save, positionOrElement) => {
    
    if (save)
    {
        var newPosition = positionOrElement;
        let text = getCurrentMenuItemText();
        
        arrMenuPosition[text] = newPosition;

        console.log(`*Page '${text}' position set to ${newPosition}`);      

    } else {
        
        currentMenuItem = positionOrElement;
        
        let text = getCurrentMenuItemText();
        console.log("*Menu click, new text is " + text);
        
        let position = arrMenuPosition[text] ?? 0;
        
        setTimeout( () => {
            isScrolling = true;
            window.scrollTo(0, position);
        }, delayBeforeRestoringPosition);
        
        console.log("*Scroll window to position " + position);
    }
}

// Function to set up individual scrollers for each menu item
var setupIndividualScrollers = () => {
    let menuItems = document.querySelectorAll(menuItemsSelector);
    
    if (menuItems.length == 0)
    {
        setTimeout(setupIndividualScrollers, 100);
    } else {
        console.clear();
        console.log(`*Console cleared for better visibility.`);
        
        menuItems.forEach(li => {
            li.addEventListener("click", function() {
                scrollHandler(false, this);
            });
        });
        
        currentMenuItem = document.querySelector(menuItemsSelector);
        
        document.addEventListener("scroll", (e) => {
            if (isScrolling == false) scrollHandler(true, window.scrollY);
            isScrolling = false;
        });
    }
};

setupIndividualScrollers();

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

Does IE 9 support endless local storage capacity?

I recently updated my HTML5 persistent storage (localStorage) capacity testing to address a memory exception issue in the previous version. I even created a jsFiddle showcasing it: http://jsfiddle.net/rxTkZ/4/ The testing code involves a loop: var val ...

Fetching JSON data from an external API using JavaScript

What is the most efficient way to load a JSON feed from an external source using JavaScript? I am familiar with PHP's file_get_contents and cURL methods, but is there a similar function or approach in JavaScript? ...

Node.js, Express continues to execute an if statement even if the condition is false

My goal is to determine whether the user signed in is an admin or not. User data is structured like this: [ { "isAdmin": "true", "_id": "60c6df22f25d381e78ab5f31", "name": "Admin", ...

Why are my elements not appearing where I want them to in absolute positioning?

Could use some help with a seemingly simple question, I just need some clarity on this issue. Background: I am working on developing a complex website and one of my ideas involves generating a series of boxes on the screen. For various reasons that are t ...

Struggling with Getting My Animation to Function Correctly

I am trying to create a JQuery Animation that will move a div covering a text box up into the border when clicked. Despite multiple attempts, I can't seem to get the animation to work properly. Any suggestions? JavaScript function moveup(title,text ...

Send information through a form by utilizing a personalized React hook

I'm having difficulty understanding how to implement a hook for submitting a form using fetch. Currently, this is what I have. The component containing the form: const MyForm = (): ReactElement => { const [status, data] = useSubmitForm('h ...

Is there a way to transform a stringified array into an array in JavaScript if I do not have access to the original string?

Recently, I encountered a challenge where I had an array of items enclosed within "", and not '' (if that distinction matters): "['item 1', 'item2', 'item 3']" I am interested in converting it to ...

What might be causing the ng-model in this plunkr to not update as expected?

I recently customized a ui-select plunkr to suit my specific needs. I've noticed that the ng-model is not updating as expected, but interestingly, clicking the button to update the model results in the ui-select getting updated. Any guidance on resol ...

Efficient Techniques to Eliminate Unwanted Jumping in CSS Transitions

I am currently working on a unique "stack" component that is inspired by the amazing ElastiStack. You can check out a cool demo of my work here. The demo works flawlessly on desktop Chrome, but unfortunately, I have encountered some issues with the transit ...

Customizing error messages to display validation errors instead of default text errors in the Django UserCreationForm

I'm encountering an issue with the registration form on my website. The form itself is straightforward, but I'm facing a problem where if a username is already taken or if the two password fields don't match, Django doesn't respond afte ...

Signs that indicate you have reached the bottom of the page

Wondering how they achieve that cool effect on where the top line appears with a new logo when you scroll down? Is it done using a jQuery trick? How can you determine when a person has scrolled down a certain amount of pixels and then show them new HTML ...

Deploying a React application to Heroku or GitHub pages can sometimes alter the appearance of styles and CSS

As a newbie to coding, I've managed to create multiple full-stack apps, but I've encountered a frustrating issue each time I deploy them to Heroku or GitHub Pages. Every element on the page seems to shrink in size compared to what it was on my lo ...

Generate Table Rows with Javascript - produces an excess of cells...>>

I am currently in the process of dynamically creating a table, but I am facing an issue with the number of cells being added. The table I am trying to create has a total of 8 columns (Monday to Friday and a total column at the end). You can view my progr ...

Creating an element in react-draggable with two sides bound and two sides open - here's how!

At the moment, I am facing an issue where the element is restricted from moving outside of the container with the class of card-width-height. My goal is to have the right and bottom sides bounded within the container while allowing the element to move beyo ...

Angular confirmation page following successful HTTP POST request to Web API

First question here... I have been given the task of improving an Angular application, even though I am starting with zero experience in Angular. While I do have some background in JavaScript, I mostly work with Java (JSP's and yes, JavaScript). Despi ...

I'm experiencing difficulty accessing the correct identification number for my questions on the website

Hi, I'm currently developing a website using Meteor where users can post questions and receive answers. I want to implement a feature that allows users to delete their own questions. When I try to directly pull the ID of the question and delete it, it ...

Trouble Aligning Bootstrap Dropdown Menu Link with Other Navbar Links

Issue with dropdown links not aligning properly in the Bootstrap navbar. The positioning seems off and can be seen in the screenshot provided where the blue outline represents the ".dropdown" https://i.stack.imgur.com/QmG7v.png Facing a similar problem a ...

Start fresh with your list styling in Sass/CSS

I'm attempting to revert ul and li elements to their default styles using a specific class, but I'm encountering difficulties in doing so. I've experimented with the inherit and initial values, but they haven't proven effective. This i ...

Is there a way to incorporate a click function into this code if the id and xpath methods are ineffective?

Check out the code snippet below: <div class="btn-group" style="margin-top: -10px; box-shadow: none !important;"> <a class="btn btn-clear store-name headerActive" style="margin-left: 0px !important;" ng-click="account();" _href="#/app ...

Steps to automatically switch Keyboard layout in APEX 5

My application is developed in APEX 5.1.2 and I'm struggling with inserting fields in RTL layout. It's cumbersome having to manually change the keyboard layout every time I work on these fields. Is there a way to have a field automatically switch ...