3

I am attempting to create an events page with a calendar, list by date, and list by location. This works by showing/hiding views with tabs controlled by JavaScript. I've put together a CodePen demo here, but keep in mind that it's missing some functionality due to having some AJAX requests, and I have not been able to reproduce the issue in this example. But you can at least look at the code and get an overview of what's happening.

The issue appears on mobile (tested on iOS) in the two list views. When I tap a link, instead of following that link, the page scrolls to the top. I am, however, able to follow the top-most link if the page is already scrolled to the top. I don't know where the issue lies, but I don't call scrollTop() or anything like that anywhere in my JavaScript. I do change the value of document.location.hash, but only when #tabs > li is targeted.

Any help is appreciated, as always. Thanks in advance.

Edit 1

As requested by Oded BD, my goToPage function, which I named tabsChildrenClick (lines 29-38):

function tabsChildrenClick($tab) {
  $tabsChildren.each(function () {
    $($(this).data('href') + 'View').hide();
    $(this).removeClass('active')
  });

  let view = $tab.data('href');
  document.location.hash = view;
  $(view + 'View').show();
}

It takes the jQuery object of the tab that triggers the change, hides all three views and makes all three tabs inactive, the takes the value of data-href (#calendar, for example) from the given $tab and uses it to update document.location.hash and show the appropriate view.

Note that I removed lines 30-33 from the original demo (at the beginning of the function), as they referred to variables in a different project and/or are not needed in this project (copy/paste error):

30 $activeTab.addClass('active');
31 galleryPage = archivePage = 1;
32 galleryEmpty = archiveEmpty = false;
33

Edit 2

I may not have stated this clearly before, but my issues lie with both list item tabs and anchor tags being clicked. The two answers that have addressed the page scrolling to the top on tab click do not address it scrolling to the top on anchor click. I hope this provides some clarification.

Edit 3

I think I know where the issue lies and why I haven't been able to reproduce it in my demo. I added a footer that hides on page scroll, so if $(window).scrollTop() == 0, the footer is visible, else if $(window).scrollTop() > 0, the footer hides. This is likely the cause of my frustration. Code to come.

Edit 4

Here's the code, but removing it didn't remove the issue as I'd hoped:

// scrolling footer
const breakpointMd = 768;
let hidden = false;
function showHideFooter() {
  let $footer = $('#footer');
  let width = $(window).width();
  let position = $('#content').scrollTop();

  if (width < breakpointMd) {
    if (position === 0 && hidden) {
      // similar to $footer.show();
      $footer.animate({
        'bottom': '0px',
      }, 500);

      hidden = false;
    } else if (position !== 0 && !hidden) {
      // similar to $footer.hide();
      $footer.animate({
        'bottom': '-49px',
      }, 500);

      hidden = true;
    }
  } else {
    hidden = false;
    $footer.css('bottom', '0px');
    $footer.show();
  }
}

$(window).on('scroll resize orientationchange', showHideFooter);
$('#content').scroll(showHideFooter);

Edit 5

I've added the scrolling footer to the demo because I still believe it is causing issues. I've updated the CodePen demo to include the footer, and now the issue has been reproduced. I've also added some return false; statements, but that hasn't helped.

One other notable change is I added a wrapper to the entire page with a <div id="grid"> tag. This may affect scrolling.

Matt McCarthy
  • 424
  • 6
  • 19
  • Are you using anchor tags within the page? If so you may need to use tabindex. There's an answer here: https://stackoverflow.com/questions/5832436/css-focus-not-working-in-safari-and-chrome – Namenone Dec 29 '19 at 17:37
  • Thank you for your suggestion, but this didn't help. It was a pain adding the values dynamically, but I suppose it's worth keeping to allow the user to tab through links. Thank you for introducing me to this attribute! – Matt McCarthy Dec 30 '19 at 14:52
  • It seems to me that You are navigating by using the `href` tags inside Your lists just only as data-attribute, is that true? So, You can avoid to use the `href` tag at all, or You need to return false in *all* Your click/tap handlers. Here is a discussion about hat topic: [Which “href” value should I use for JavaScript links, “#” or “javascript:void(0)”?](https://stackoverflow.com/questions/134845/which-href-value-should-i-use-for-javascript-links-or-javascriptvoid0) – deblocker Jan 04 '20 at 12:37
  • can you show your goToPage function? – Oded BD Jan 05 '20 at 19:31
  • See my edit. I believe the function you're requesting is what I called `tabsChildrenClick()`, but let me know if that's not what you meant. – Matt McCarthy Jan 05 '20 at 21:52
  • Is your website displayed within an iframe? – clamchoda Jan 07 '20 at 19:40
  • It is not displayed within an iframe. – Matt McCarthy Jan 07 '20 at 23:56

2 Answers2

0

I guess there are two ways to do this.

Option 1: event.preventDefault()

Call the .preventDefault() method of the event object passed to your handler. If you're using jQuery to bind your handlers, that event will be an instance of jQuery.Event and it will be the jQuery version of .preventDefault(). If you're using addEventListener to bind your handlers, it will be an Event and the raw DOM version of .preventDefault(). Either way will do what you need.

Examples:

$('#ma_link').click(function($e) {
    $e.preventDefault();
    doSomething();
});

document.getElementById('#ma_link').addEventListener('click', function (e) {
    e.preventDefault();
    doSomething();
})

Option 2: return false;

In jQuery:

Returning false from an event handler will automatically call event.stopPropagation() and event.preventDefault()

So, with jQuery, you can alternatively use this approach to prevent the default link behaviour:

$('#ma_link').click(function(e) {
     doSomething();
     return false;
});

If you're using raw DOM events, this will also work on modern browsers, since the HTML 5 spec dictates this behaviour. However, older versions of the spec did not, so if you need maximum compatibility with older browsers, you should call .preventDefault() explicitly. See event.preventDefault() vs. return false (no jQuery) for the spec detail.

Akshay
  • 559
  • 2
  • 11
  • These do not solve the issue. I have no click event handler for the anchor tags below the tabs, and as I expected, adding one doesn't help. The issue must lie somewhere else in my code. – Matt McCarthy Jan 08 '20 at 18:28
0

Modifying document.location.hash will cause the browser to scroll to that element. If there are no elements with that ID on the page, then it'll scroll to the top of the page.

Why not use

history.pushState({}, '', '#' + view);

or

history.replaceState({}, '', '#' + view);

instead?

 

See more solutions here: Modifying location.hash without page scrolling

 

Edit: Looking at the codepen you've provided more closely, I see there are two places where you have the following line.

document.location.href = '#' + context['day'];

Replacing them with

history.pushState({}, '', '#' + context['day']);

should fix the issue in the codepen you've linked.

Eliezer Berlin
  • 3,170
  • 1
  • 14
  • 27
  • There are two places where you use "document.location.href = '#' " in your codepen. Perhaps my edited answer will help. – Eliezer Berlin Jan 09 '20 at 21:12
  • I saw your edit, and making those changes did not help. It appears to work better when I edit `document.location.href`, at least in the case where I tap on a calendar cell to view the date under "by Date." – Matt McCarthy Jan 09 '20 at 22:21
  • Has this been resolved? I don't see any scrolling on the page, when clicking on any of the buttons in the codepen. – Eliezer Berlin Jan 10 '20 at 06:39
  • It has not. It works on desktop, but not mobile. Could it be because I'm using an older iPhone? – Matt McCarthy Jan 10 '20 at 21:57