How to get consistent ScrollIntoView behavior - javascript

So I have been using ScrollIntoView() to jump to anchors in a react component as part of a web app. For small pages, it works fine, goes to the right spot and behaves as one would expect. I have one larger page where the behavior is strange. On loading, the jump to anchor is below where it should be by half a page or more. The first time one clicks on a link to any anchor, including the same anchor, the anchor ends up above where it should be by a similar amount. Every subsequent click after that works perfectly as long as the page is not reloaded. Here is my code for the function. It has a setTimeout because I thought that the problem had something to do with the page loading, but there is no effect. Here is my function:
scrollToAnchor: function () {
let anchorName = this.props.location.hash || window.location.hash;
if (anchorName) {
anchorName = anchorName.replace("#", "");
let anchorElement = document.getElementById(anchorName);
if (anchorElement) {
window.setTimeout(anchorElement.scrollIntoView(true), 0);
}
} else {
window.scrollTo(0, 0);
}
},

In my case, I had to add the default params manually in order for it to work in some browsers. The block and inline params have an associated default value, but I had to put them in manually like this:
my_element.scrollIntoView(
{ behavior: 'smooth' , block: 'start', inline: 'nearest'}
);
Once I defined them in the scrollIntoViewOptions, it worked fine across all browsers.
PS: don't forget the polyfill for smooth scrolling.

Related

How to go to particular section without scrolling behavior / Any alternative to scrollIntoView() without scroll behavior?

I am trying to create a page redirection to a particular section, i.e. I want to go to a particular anchor div on a page without scrolling behavior. However, I have a query string in the URL for pagination so the #id method failed for me. I tried "scrollIntoView()" but it contains the page scrolling behavior, which is undesired. May I ask if there is any alternative solution to this problem?
I am using Vue for the frontend & Codeigniter for the backend. Here is my code:
mounted() {
// anchorPageToProductList
if (this.isOnQuery) {
console.log('isOnQuery');
this.scrollToProductList();
} else {
console.log('isNotOnQuery');
}
},
methods: {
scrollToProductList(){
window.addEventListener('DOMContentLoaded', () => {
// scroll animation
document.getElementById('product-list-anchor').scrollIntoView(true);
});
},
Example of my URL case:
http://www.example.com/Product/list?search=&sort=3&type=-1&event%5B%5D=11&pagination=1
Thank you!!
I've tried to unset the scrolling behavior, allow the the page to jump to the desired section, then set back the smooth-scroll behavior. So It now works without the scrolling behavior. Thanks for all the comments:)
My code:
scrollToProductList(){
window.addEventListener('DOMContentLoaded', () => {
// select the whole html & disable smooth-scroll behavior in css
let htmlElement = document.querySelector('html');
htmlElement.style.scrollBehavior = 'auto';
// go to the anchor point
document.getElementById('product-list-anchor').scrollIntoView(true);
// enable smooth-scroll behavior again
htmlElement.style.scrollBehavior = 'smooth';
});
}

Issues loading in javascript on single page website when navigating away and then returning

Here is my website: https://memsmosaics.com/
I'm trying to make my website a single page website. When the website initally loads at index.html, it works as intended. At this time bottom section is loaded in nicely from gallery.html by the following function:
<script>
$(document).ready(function() {
$('#js-content').load('/gallery.html');
$('#js-navigation a').click(function(e) {
e.preventDefault();
$("#js-content").load(e.target.href);
})
});
</script>
When I navigate to the about section, and then return back to the home section by clicking on 'memsmosaics' in the top left, the gallery section no longer works as it should. It looks like the javascript is no longer applied to do things it was doing before - like aligning the images, and filtering by 'sold' and 'for sale'.
I have tried moving the relevant script tags from index.html to gallery.html, but this hasn't solved the problem. I'm not sure what else to try.
Thanks for any help!
You could listen for a popstate event after load, like this:
const initGallery = () => {
if(location.hash === '#new-section' || location.path === '/') {
$('#js-content').load('/gallery.html');
$('#js-navigation a').click(function(e) {
e.preventDefault();
$("#js-content").load(e.target.href);
})
}
}
window.addEventListener('popstate', initGallery)
$(document).ready(initGallery);
That is triggered during navigation. Here's an article that provides a bit more insight: https://gomakethings.com/how-to-detect-when-the-browser-url-changes-with-vanilla-js/
Edit with explanation:
The problem you're running into is your handlers are being added only on load, so when the gallery is removed, you have detached DOM nodes hanging around, and they're never re-attached because the load event only fires on the initial page load. This creates a memory leak.
You can learn more about detached DOM nodes here: https://www.tutorialspoint.com/how-can-detached-dom-elements-cause-memory-leak-in-javascript
You could update the code above to remove the click listener. I'm not too familiar with jQuery, but the docs demonstrate an off method, so your updated code could look like this alternatively:
const initGallery = () => {
const onClick = (e) => {
e.preventDefault();
$("#js-content").load(e.target.href);
}
const btn = $('js-navigation a')
if(location.hash === '#new-section' || location.path === '/') {
$('#js-content').load('/gallery.html');
btn.click(onClick)
return
}
if(btn) {
btn.off('click', onClick)
}
}
This should work, per the definition of popstate:
When the transition occurs, either due to the user triggering the browser's "Back" button or otherwise, the popstate event is near the end of the process to transition to the new location.

jQuery history usage

I have created a webpage that uses jQuery to show and hide elements. The obvious problem now arose; the back and forward browser buttons don't work anymore as everything is loaded within a single location.
I know the answer lies within jQuery History but after busting my head for several hours on their website and examples given here on stackoverflow, I still cant manage to:
A) create a history entry (I think i got this covered but not 100% sure)
B) animate the page transition with my own function (displayed beneath)
This is the website: www.grommit.nl
There are 4 sub-pages that require a history entry when called upon.
This code shows the transition of the "wordpress page". The other pages work in a similiar way. (so far I have only managed to generalize the last part of the pageload with the "LoadPageContent" function, the bit before that is different with every page)
var LoadPageContent = function() {
$(".sceneBody").slideDown(function() {
$(".aftertitle").css('width', '4em');
$(".mediacontainer").fadeTo('0.3s', 1,)
});
$("#goWordpress").click(function () {
$("#homeScene").fadeOut(function () {
$("#wordpressMessage").fadeIn(function() {
$(this).delay(300).slideUp(function() {
$("#wordpressPage, #grommitFixed").slideDown(function() {
LoadPageContent();
});
});
});
});
});
this is the function that is currently working as a previous button within the DOM. I would like this function to execute when the previous button is clicked.
var goBack = function() {
$(".aftertitle").css('width', '0em')
$(".mediacontainer").fadeTo('0.3s', 0, function() {
$(".scenebody, #grommitFixed").slideUp(function() {
$("*[id*=Page]:visible").each(function() {
$(this).slideUp(function() {
$("#homeScene").fadeIn();
});
});
});
});
};
In html5 you have something called pushstate, that you can use to tell the browser what to go back to. Check out:
html pushstate

iscroll scrollToElement not updating currPage variable

UPDATE:
I was able to get my scroller working as desired but I feel like I have hacked around the actual issue and would love it if anyone has a more solid answer, I've updated and noted in the snippets below the new jQuery I'm using.
I'm using iScroll-4 (http://cubiq.org/iscroll-4) for an iPad/Android web app, everything's working perfectly with the swipes and scrolling but I have a table of contents at the beginning of the app that allows users to jump to specific areas of the scroller --
I'm using the iScroll function scrollToElement(element, duration) in order to jump to the different areas. Also using scrollToPage(page, duration) to allow the user to manually navigate forward and backward one page at a time.
While watching the console logs the currPageX variable updates when I navigate with the scrollToPage function and when I swipe, but when using the scrollToElement the currPageX variable does not update.
Therefore if I jump to an element and then navigate forward with scrollToPage('next', 0) it will go backwards and navigate me to the next page after the table of contents.
I have tried using the scroll.refresh() function after scrollToElement, before, putting the function inside a timeout, etc. and I can't figure out why the currPageX is not updating.
Here's a snippet of the jQuery code that I'm using the two different functions:
// TO NAVIGATE FORWARD AND BACKWARDS
$('span.control').on('click', function() {
var slideDir = $(this).attr('data-dir');
if (slideDir == 'prev') {
var tehPg = tehScroll.currPageX-1;
} else if (slideDir == 'next') {
var tehPg = tehScroll.currPageX+1;
}
tehScroll.scrollToPage(tehPg, 0);
return false;
});
// TO JUMP FROM CONTENTS
$('li[data-page="toc"] span').on('click', function() {
var toPage = $(this).attr('data-page');
tehScroll.scrollToElement('li[data-page="'+toPage+'"]', 800);
// ADDED THE FOLLOWING LINE TO MANUALLY SET currPageX after scrolling!
tehScroll.currPageX = $('#slides li[data-page="'+toPage+'"]').index();
return false;
});
Did you consider using jquery-mobile-iscrollview widget plug-in? - there is a function scrollToPage(pageX, pageY, time), works well for me...
best
M

Using jQuery-Smooth-Scroll from one page to another?

I am currently using jQuery-Smooth-Scroll to smoothly scroll up and down to various anchor positions on one of my pages (Page 1). However, what I would also like to be able to do is, from another page (Page 2), link to Page1 (appending #bookmark to the url) and have jQuery-Smooth-Scroll pick up on the fact I am calling the page with a #bookmark and have it smoothly scroll down to the relevant position once the page has completed loading. I don't know if this is a possibility or not?
This is the version of Smooth-Scroll that I'm using:
https://github.com/kswedberg/jquery-smooth-scroll
I'm still relatively new to jQuery so I may be overlooking something obvious.
Ajma's answer should be sufficient, but for completeness:
alert(location.hash)
Edit: a more complete example:
// on document.ready {
if (location.hash != '') {
var a = $("a[name=" + location.hash.substring(1) + "]");
// note that according to w3c specs, the url hash can also refer to the id
// of an element. if so, the above statement becomes
// var a = $(location.hash);
if (a.length) {
$('html,body').animate({
scrollTop: $(a).offset().top
}, 'slow');
}
}
// }
It's possible, you want to put a call into the smooth scroll function when the page is finished loading. in jQuery, it's using $(document).ready(function () { your code } );
You'll need to put something in to parse your url to extract the #bookmark and then call the smooth scroll.

Categories