mdNavBar doesn't update from URL with Angular

2019-07-29 04:26发布

问题:

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?

回答1:

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.



回答2:

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