0

On an application my team and I are working on, we're observing some inconsistent behavior. When a user performs a browser refresh, the refresh button fully refreshes the page including UI state...but only does that up to a certain route.

Our App starts on the /Home route, which sets up the overall application, as well as the component hierarchy. The user proceeds to A.A, A.B, A.C, which all function fine. B.A works fine as well.

Then, trouble. If you perform a browser refresh from B.B or B.C, you get returned to B.A. We expect that the end-user would be returned to B.B or B.C if they refresh from those pages.

Routes.ts

    $stateProvider
        .state('Home',
        {
            url: '/Home',
            templateUrl: 'App/Home/home.html',
            controller: 'homeCtrl',
            controllerAs: '$ctrl'
        })
        .state('A',
        {
            url: '/A',
            templateUrl: 'app/A/A.html',
            controller: 'aCtrl',
            controllerAs: '$ctrl'
        })
            .state('A.A',
            {
                url: '/A.A',
                component: 'aPartA'
            })
            .state('A.B',
            {
                url: '/A.B',
                component: 'aPartB'
            })
            .state('A.C',
            {
                url: '/A.C',
                component: 'aPartC'
            })
        .state('B',
        {
            url: '/B',
            component: 'b'
        })
            .state('B.A',
            {
                url: '/B.A',
                component: 'bPartA'
            })
            // Beyond this part, oddness starts...
            .state('B.B',
            {
                url: '/B.B',
                component: 'bPartB'
            })
            .state('B.C',
            {
                url: '/B.C',
                component: 'bPartC'
            });

    $urlRouterProvider.otherwise('/Home');

    $locationProvider.html5Mode({ enabled: true});

The way we actually perform our routing, is using a component!

Relevant HTML:

<order-navigation validate-view="$ctrl.validate(someForm)"
     previous-route="A.C"
     previous-button-text="previous"
     next-route="B.A"
     next-button-text="continue">
</order-navigation>

Order Navigation Component Controller:

export class OrderNavigationCtrl implements angular.IController {
    //#region Variables / Properties

    public nextRoute: string;
    public previousRoute: string;
    public nextButtonText: string;
    public previousButtonText: string;
    public validateView : () => boolean;

    //#endregion Variables / Properties

    //#region Constructor

    public static $inject: string[] = ['$state', '$window'];
    constructor(
        private $state: angular.ui.IStateService,
        private $window: angular.IWindowService) {
    }

    public $onInit(): void {

    }

    //#endregion Constructor

    //#region Methods

    public navigatePrevious(route: string): void {
        if (route.search('www') > 0)
            this.$window.open(route, '_self');
        else
            this.$state.go(route);
    }
    public navigateNext(route: string): void {
        if (this.validateView())
            this.$state.go(route);
    }

    //#endregion Methods
}

I've checked each page's HTML, and found no typos that would cause B.B or B.C to redirect to B.A. As we're using a common component, I would expect that if the flaw were in the component controller, it would affect all pages equally, and cause any page refresh to fall back to a common point, which is not the case.

Questiosn: A: What's causing B.B and B.C to redirect to B.A, instead of themselves?
B: In what way can I change this to ensure that B.B and B.C redirect to themselves?

Possible Workaround: One thing my research has suggested that I can do is to use localStorage and .run() to cache the UI router state. I would like to avoid this, because ideally this routing should 'just work'; we're not doing anything special. If there is something we're doing incorrectly in this, I also need to know what it is, so that my team and I don't do that incorrect thing.

Andrew Gray
  • 3,756
  • 3
  • 39
  • 75

1 Answers1

0

The problem was that the 'B' 'trunk' route was incorrect. It should be:

.state('B', {
    url: '/B',
    templateUrl: 'app/A/A.html',
    controller: 'aCtrl',
    controllerAs: '$ctrl'
})
    .state('B.A', {
        // ...Other B substates here...
    })

It appears that, defining a 'trunk' view as a component has some awkward relationships with the UI router setup. Instead, a trunk view should always be defined in a more classic manner, with the URL, controller/controller as setup defined. When this happens, child component states can work in the manner that we expect.

Andrew Gray
  • 3,756
  • 3
  • 39
  • 75