Single Page App in a Single Page App

I am integrating Ember.js in an HTML SPA which has <a href="#to_section_home">Home</a> navigation.

Just wondering how to do this in Ember if anyone has an idea. Would still like history and URL to work as usual but that seems unlikely.

You can tell Ember to leave the URL alone like this:

App.Router.reopen({
  location: 'none'
});

But yes, this means you’ll lose the ability to navigate the Ember app using the normal browser forward & back controls. It’s not great.

If you can change the existing single page app a little, you could make them coexist by putting each in charge of different URLs.

Well I did a rewrite on the navigation of the App. My take was…

In Navigation HBS file.

<ul class="navigation menu">
    <li><a href="#/" {{action goToLink "home" "to_the_top"}}>Home</a></li>
    <li><a href="#/" {{action goToLink "home" "top_center"}}>Services</a></li>
    <li><a href="#/" {{action goToLink "blog" "main_top"}}>Technology</a></li>

In ApplicationRoute JS file:

var ApplicationRoute = Ember.Route.extend({
    actions: {
        goToLink: function(route, scrollToDiv) {
            var $scrollTo = smoothScroll(scrollToDiv);
            this.transitionTo(route).then($scrollTo);
        }
    }
});

Then I have a smooth scrolling JS function that I am not sure where to put or whether to put this in an Handlebars helper or something else.

var smoothScroll = function(e) {
	var destinationLink = document.getElementById(e);

	// If we didn't find a destination, give up and let the browser do its thing
	if (!destinationLink) return true;

	// Find the destination's position
	var destx = destinationLink.offsetLeft; 
	var desty = destinationLink.offsetTop;
	var thisNode = destinationLink;
	while (thisNode.offsetParent && (thisNode.offsetParent != document.body)) {
  	   thisNode = thisNode.offsetParent;
  	   destx += thisNode.offsetLeft;
  	   desty += thisNode.offsetTop;
	}

	// Stop any current scrolling
	clearInterval(self.INTERVAL);

	var cypos = getCurrentYPos();
	var STEPS = 25;
	var ss_stepsize = parseInt((desty-cypos)/STEPS);

	self.INTERVAL = setInterval(function() {
	    var wascypos = getCurrentYPos();
	    var isAbove = (wascypos < desty);
	    window.scrollTo(0,wascypos + ss_stepsize);
	    var iscypos = getCurrentYPos();
	    var isAboveNow = (iscypos < desty);
	    if ((isAbove != isAboveNow) || (wascypos == iscypos)) {
	      // if we've just scrolled past the destination, or
	      // we haven't moved from the last scroll (i.e., we're at the
	      // bottom of the page) then scroll exactly to the link
	      window.scrollTo(0,desty);
	      // cancel the repeating timer
	      clearInterval(self.INTERVAL);
	      // and jump to the link directly so the URL's right
	      //location.hash = anchor;
	    }
	},10);

	function getCurrentYPos() {
		if (document.body && document.body.scrollTop)
		  return document.body.scrollTop;
		if (document.documentElement && document.documentElement.scrollTop)
		  return document.documentElement.scrollTop;
		if (window.pageYOffset)
		  return window.pageYOffset;
		return 0;
	} 
}

This is based on SmoothScroll.js by kryogenix but a much simpler version. I think this would make a good pure helper or perhaps even an extension to Link-To.

@wycats, @tomdale do you guys think internal linking and some type of smooth scrolling is worthy of a PR on the link-to helper of is this something that is not of enough value to have in the core implementation?

1 Like