3
votes

I'm using angular-ui-router in an AngularJS SPA along with the bootstrap tabset directive.

Here is my example http://plnkr.co/V0Cs6BfnggXshawMv4LX and the steps to reproduce the problem.

  • Launch the plunker in "Full Screen" so the page can be easily reloaded.
  • Click on the "Child Two" tab.
  • The URL in the browser correctly shows the state as /home/child2
  • Reload the page.
  • URL in the browser still shows the state as /home/child2

The problem is the UI of the tabset now shows the "Child One" tab selected even though the state is "home.child2". Is there an automatic way to for the tabs to show the right state?

4

4 Answers

2
votes

I did this without the tab array and the $stateChangeSuccess... There is one work-around still.

This will control clicking and the active status:

<tab ui-sref="home.child1" ui-sref-active="active"></tab>

For me, the ui-view does not work inside of the tab elements when the page is refreshd or loaded initially from the url. They only worked when the tabs were clicked. So, a work-around is to list the ui-views underneath the tabset.

<tabset><tab ui-sref="home.child1" ui-sref-active="active"></tab></tabset>
<div ui-view="home.child1"></div>

Now, only the correct ui-view will show on refresh and click nav works.

I'm not sure if this is specific to my app; but the first tab was always active. A disabled tab as the first tab was the work-around: <tab disabled="true"/>

1
votes

I had the same problem few days ago. After some research, I found a solution that might help you:

States configuration

angular.module('app', [
'ui.router'
])

.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) {

    $urlRouterProvider.otherwise('home'); // For any unmatched url, redirect to home.

    $stateProvider
        .state('home', {
            url: '/home',
            templateUrl: "", // First template.
            controller: "homeController"
    })

        .state('home.child1', {
            url: '/child1',
            templateUrl: "", // Second template.
            controller: "homeController"
    })
        .state('home.child2', {
            url: '/chil2',
            templateUrl: "", // Third template.
            controller: "homeController"
    })
        .state('home.childn', {
            url: '/chiln',
            templateUrl: "", // n template.
            controller: "homeController"
    });
}])

The controller

.controller('homeController', ['$scope', '$state', function($scope, $state) {

$scope.active = function(route) {
    return $state.is(route);
};

$scope.tabs = [
    { heading: "Home", route:"home", active:false }, // Tab 1
    { heading: "Child One", route:"home.child1", active:false }, // Tab 2
    { heading: "Child Two", route:"home.child2", active:false }, // Tab 3
    { heading: "Child n", route:"home.childn", active:false } // Tab n
];

$scope.$on("$stateChangeSuccess", function() { // Keep the right tab highlighted if the URL changes.
    $scope.tabs.forEach(function(tab) {
        tab.active = $scope.active(tab.route);
    });
});
}]);

Last but not least, the HTML

<tabset>
<tab 
ng-repeat="tab in tabs" 
heading="{{ tab.heading }}"
ui-sref="{{ tab.route }}"
active="tab.active">
</tab> 
</tabset>

Here is the demo.

0
votes

One way I've found is to add a filter to each of the tabs to set it's active state to true if that tab's state is the current state.

<tab heading="Heading For First Tab" active="('home.tab1' | isState)" />

and that works but as a side-effect an exception is generated on the $watch that the framework puts on 'active'.

0
votes

            <li heading="Status" class="ng-isolate-scope var" ng-model="(var = 'active: active')" >
                <a href="/1">Status1</a>
            </li>


            <li heading="Status" class="ng-isolate-scope var" ng-model="var = 'active: active'">
                <a href="/2">Status</a>
            </li>


    </tabset>