1

I'm using Angular 1.6 and ui-router 1.0.0-rc.1. I set up a couple of simple states:

.config(function($stateProvider) {
    $stateProvider.state({
        name: "foo",
        url: "/foo",
        template: "<foo-widget layout='row'/>"
    });

    $stateProvider.state({
        name: "bar",
        url: "/bar",
        template: "<bar-widget layout='row'/>"
    });

    $stateProvider.state({
        name: "home",
        url: "",
        template: "<foo-widget layout='row'/>"
    });

Then on the main page I put an mdNavBar:

<md-nav-bar nav-bar-aria-label="navigation links" md-selected-nav-item="foo">
    <md-nav-item name="foo" md-nav-sref="foo">Foo</md-nav-item>
    <md-nav-item name="bar" md-nav-sref="bar">Bar</md-nav-item>
</md-nav-bar>

When I click on "Foo" it takes me to http://example.com/example/#!/foo, and when I click on "Bar" it takes me to http://example.com/example/#!/bar.

But when I manually enter the URL http://example.com/example/#!/foo, the Foo nav-item is not selected, even if it was already selected. Also if I enter the URL http://example.com/example/#!/bar, the Bar nav-item is not selected, even though the state apparently changes to "bar" (based upon my embedded components.

Why isn't the mdNavBar following the current ui-router state?

Garret Wilson
  • 18,219
  • 30
  • 144
  • 272

2 Answers2

2

EDIT: Adapted to ui-router 1.0.0-rc1 version. Plunker avaibale here

I think you could solve it keeping the md-selected-nav-item in the ui-router state data.

  1. Add the selectedItem to each ui-router state data. Something like this:

$stateProvider.state({
    name: "foo",
    url: "/foo",
    data: {
      'selectedItem': 'foo'
    },      
    template: "<foo-widget layout='row'/>"
});

$stateProvider.state({
    name: "bar",
    url: "/bar",
    data: {
      'selectedItem': 'bar'
    },              
    template: "<bar-widget layout='row'/>"
});
  1. In your main controller (in the same controller constructor), update the selectedItem every time the state is changed. You can do it watching the event $transitions.onSuccess. Example:

myApp.controller('HelloWorldCtrl', function($scope, $transitions) {
  $scope.selectedItem = "";

  $transitions.onSuccess({}, function(trans) {
    $scope.selectedItem = trans.to().data.selectedItem;
  });
});
  1. In your main html page, bind md-selected-nav-item to the scope selectedItem variable.

<md-nav-bar nav-bar-aria-label="navigation links" md-selected-nav-item="selectedItem">
    <md-nav-item name="foo" md-nav-sref="foo">Foo</md-nav-item>
    <md-nav-item name="bar" md-nav-sref="bar">Bar</md-nav-item>
</md-nav-bar>   

I was facing with the same problem with md-tabs, and this wordked for me. I believe it should work pretty well for md-nav-bar too.

Hope it helps.

Garret Wilson
  • 18,219
  • 30
  • 144
  • 272
troig
  • 7,072
  • 4
  • 37
  • 63
  • Been there, tried that. `$stateChangeSuccess` is now deprecated and disabled by default. https://ui-router.github.io/guide/ng1/migrate-to-1_0#state-change-events . And please indicate _where_ I put the event-listening code --- in the controller "constructor" method? In `$onInit()`? Please provide a tested solution using the latest (indicated) versions. Thanks. – Garret Wilson Apr 20 '17 at 21:49
  • About where put the event-listening, you can do it in the controller constructor. On the other hand, you're absolutely right: the $stateChangeSuccess is deprecated....I've not upgraded to 1.0 yet and didn't know that. I'll try to provide an example with the latests versions, it should not be difficult. – troig Apr 20 '17 at 22:18
  • 1
    "…it should not be difficult." @troig Famous last words. ;) That's what I thought. – Garret Wilson Apr 21 '17 at 00:50
  • @GarretWilson hahaha! Bad words ;) I've tried to make an attempt with ui-router 1.0 (answer updated, basically point 2). Could you check my edit and let me know your thoughts.Hope it helps – troig Apr 21 '17 at 09:42
  • 1
    This is just awesome. Your answer and response to feedback is a model of how questions should be answered on Stack Overflow. You not only helped me out with this problem, it helped me address a different problem as well; see http://stackoverflow.com/a/43553641/421049. My biggest problem was that `$transition` was completely new to me and I wasn't sure where to start. With your help and examples, I was able to jump into the documentation. Note that if you want to match all transitions (as per the docs), you can simply use `{}` as in `$transitions.onSuccess({}, function(trans) {…});`. Thanks! – Garret Wilson Apr 21 '17 at 23:56
  • You're welcome @Garret Wilson, glad to help :) SO is helping me every day, the least I can do is giving back something to the community whenever I can. And good catch your answer concerning the other problem you found it. – troig Apr 22 '17 at 08:12
0

It's possible to pre-select navigation item by setting value for attribute md-selected-nav-item on md-nav-bar. Value should be the same as md-nav-item name attribute.

<md-nav-bar md-selected-nav-item="$ctrl.currentNavItem" nav-bar-aria-label="navigation links">
    <md-nav-item ng-repeat="page in $ctrl.pages" md-nav-sref="{{page.state}}" name="{{page.name}}">{{page.label}}</md-nav-item>
</md-nav-bar>

Controller should set the value to expected. Wrap it in something to notify angular digest cycle about changes ($timeout in my case)

panelController = (_, $timeout, $state, Routes) ->
  @pages = [
    state: Routes.tooltips
    name: 'tooltips'
    label: 'Helpers'
  ,
    state: Routes.events
    name: 'events'
    label: 'Events'
  ,
    state: Routes.users
    name: 'users'
    label: 'Users'
  ]

  $timeout =>
    @currentNavItem = _.find(@pages, state: $state.current.name).name

  return this
paragonid
  • 241
  • 2
  • 8