0

This is an extention of 2 previous questions; How do I use angular ng-hide based on the page/route that I am currently on? and How can I use ng-hide if $location.url == base (root) url? Both concern the display of navigation items, using $location.path(), dependent upon the current route.

I have a very simple contact-list style SPA with just a header, footer and various views. The header has 3 navigation buttons. Each uses a function bound to ng-click to change the path and a boolean test for display, e.g.

<button ng-click="changePath('/summary')" ng-hide="path == '/summary' ">Summary</button>

Inside the attached HeaderController, with the $location service injected, we have.

var vm = this;
vm.path = $location.path();
vm.changePath = changePath;

function changePath (newPath) {
    this.path = newPath;
    $location.path(newPath);
}

This all works as expected except for two instances.

Firstly, when the app is first loaded. The default route configuration is set to .otherwise({redirectTo : "/summary"}but the summary button still appears.

Secondly, when the route is altered from inside a page view with a different controller. For example, from the summary page each contact has a link that will load a new page with all the details.

<div ng-repeat="data in contacts">
    ...
    <span ng-click="showDetails(contacts.indexOf(data))">Info</span>
</div>

and the associated SummaryController again just uses $location to change the route

var vm = this;
vm.contacts = dataStore.getDetails();
vm.showDetails = showDetails;

function showDetails(index) {
    $location.path("/details/" + index);
}

As before, this works as expected; the view with the appropriate details is displayed but the navigations buttons are not updated.

In both instances a simple browser page-refresh displays the correct navigation buttons.

My understanding was that $location should broadcast the route change https://stackoverflow.com/a/12429133/2980217. The page refresh, however, suggests that perhaps the $digest cycle needs to be triggered by a call to $apply but that just seems wrong.

I've tried wrapping $location.path() inside $timeout as per this answer https://stackoverflow.com/a/24144088/2980217 but that hasn't worked.


Edited 2 Dec: I have created a skeleton version of the app as a plunk http://plnkr.co/edit/7bQn6G9HveHajBMdrDfR.

For the app loading issue, it appears that the template loads first at which point $location.path() is a empty string. To overcome this I have used a simple conditional to manually set the currentPath variable.

What I appear to need is a page refresh. According to this article https://www.sitepoint.com/premium/books/angularjs-novice-to-ninja/preview/exploring-the-location-service-2f17ca5 using $window.location.href is the way to go. I've given this a go but without success.

Perhaps I'm going about this completley the wrong way. Any advice would be gratefully appreciated.

Thank you.

Community
  • 1
  • 1
magwitch
  • 29
  • 6

1 Answers1

0

The answer is here: https://stackoverflow.com/a/24831979/2980217.

Very simply: use a custom service to handle all the changes to the path.

  • Angular's $location service can be injected into this service.
  • Inject this service into each controller where the path gets changed.
  • The new service uses $rootScope to broadcast the change. $rootScope.$broadcast("pathChanged", newPath);
  • The controller for the navigation buttons listens for the broadcast and updates its model for the current path accordingly. This triggers the view (i.e. the navigation buttons) to be displayed or hidden as required.

    $scope.$on("pathChanged", updatePath)
    
    function updatePath(evt, updatedPath) {
       vm.currentPath = updatedPath;
    }
    

The updated Plunk is here: http://plnkr.co/edit/7bQn6G9HveHajBMdrDfR

Community
  • 1
  • 1
magwitch
  • 29
  • 6