Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple views on one page with history in AngularJS using Angular UI Router

In my AngularJS app, I have an about page with several sub-sections. All these sub-sections are on the same page and part of the same template. However I want to access each section via it's own URL that will scroll down to the correct section if it matches.

I've set up the states as so:

.state('about', {
    url: "/about",
    templateUrl: "partials/about.html",
})
.state('about.team', {
    url: "/about/team",
    templateUrl: "partials/about.html"
})
.state('about.office', {
    url: "/about/office",
    templateUrl: "partials/about.html"
})
.state('about.other', {
    url: "/about/other",
    templateUrl: "partials/about.html"
});

And on the about page I have a menu like:

<div class="menu">
    <a ui-sref-active="selected"
    ui-sref="about.team">The Team</a>
    <a ui-sref-active="selected"
    ui-sref="about.office">The Office</a>
    <a ui-sref-active="selected"
    ui-sref="about.other">Other</a>
</div>

This menu is fixed at the bottom and when the user clicks the link or when visiting the url direct via the address bar it should scroll to that section (updating the url where need be to match it).

However I'm not sure how to do this (via Angular). To summarize:

  1. How can I scroll to the different sections on the same page via the URL? As I can't use the standard hash trick as it already uses hashes for the address (we support IE8). And I don't want to use hashes at all when in HTML5 mode! It should also scroll to the section on page load AFTER the app has loaded, so need some way of firing the code that scrolls the user after something else...
  2. How can I make this work on click of the buttons? Currently when clicking the buttons, they change the URL but don't scroll to the content.

The HTML for the page looks Like: http://pastebin.com/Q60FWtL7

You can see the app here: http://dev.driz.co.uk/AngularPage/app/#/about

For an example of something similar (https://devart.withgoogle.com/#/about/your-opportunity) as you can see it scrolls down to the correct section based on the url AFTER the page has loaded... and doesn't use a hash but the ACTUAL url.

like image 756
Cameron Avatar asked Aug 28 '14 10:08

Cameron


2 Answers

You can try this approach where you create a directive which triggers the scroll on click. You can add this directive to your link as an attribute. where the sref attribute will be the id of the target div.

app.directive('scrollTo', function() {
  return {
    link: function(scope, element, attrs) {
    element.bind('click', function() {
      var divPosition = $(attrs.sRef).offset();
      $('html, body').animate({
      scrollTop: divPosition.top
      }, "slow");

    });
   }
  };
});

Plunker

like image 55
samir Avatar answered Sep 20 '22 05:09

samir


ui-router doesn't place restrictions on the signature of your state object, so you can simply add a property:

  .state('about.office', {
     url: "/about/office"
    ,templateUrl: "partials/about.html"
    ,scrollToId = "divAboutOffice";
  })

Then your controller can access this data when you inject the $state service.

  $('html, body').animate({
    scrollTop:  $($state.current.scrollToId).offset().top
  }, "slow");

assuming you included the id="divAboutOffice" in your HTML. (and assuming my jQuery reference was correct; I don't use jquery so I'm not sure.) Depending on your needs, you would wrap that animate() in an $on() for one of the events: $locationChangeSuccess), $routeChangeSuccess, or $stateChangeSuccess

also: You don't have to use the "id", as I have - You could leverage the existing ui-sref if you really want to search for elements by attribute. In your example that appears to match $state.current.name

like image 39
bcombs Avatar answered Sep 23 '22 05:09

bcombs