Question

I'm using UI-Router in my AngularJS app and I have routes like this:

angular.module('app.messages').config(function($stateProvider, ACCESSLEVELS) {
    $stateProvider.state('messages', {
        url: '/messages',
        templateUrl: 'messages/list.html',
        controller: 'MessagesListCtrl as controller',
        resolve: {
            'conversations': function(Restangular) {
                return Restangular.all('conversations').getList();
            }
        }
    });

    $stateProvider.state('messages.detail', {
        url: '/{conversationId:[0-9]{1,8}}',
        templateUrl: 'messages/conversation.html',
        controller: 'MessagesDetailCtrl as controller',
        resolve: {
            'conversation': function(conversations, $stateParams) {
                return conversations.get($stateParams.conversationId);
            }
        }
    });
});

So if you go to /messages it'll show a list of your conversations (and it contains a ui-view for the details view). If you go go /messages/1 you view a single conversation.

When you go to /messages you should automatically be redirected to the most recent conversation, because just showing the list and a message like "Select a conversation from the list" is just stupid :)

The problem is that I don't know how to do this. If I have some redirect logic in the MessagesListCtrl then you'll always have a delay where you see the empty landing page and are then redirected. I can't do it a resolve function since those are also used by the child state. Surely others have had this same problem, how did they solve this?

Was it helpful?

Solution

Make messages an abstract state, keep the resolve, and move the templateUrl and controller to a new state, messages.list. Then, create a parent <ui-view /> for your messages state, and give it a templateUrl with whatever you want the user to see while the message is loading. Should work.

OTHER TIPS

Solved with the help of Nate's answer above:

angular.module('app.messages').config(function($stateProvider) {
    $stateProvider.state('messages', {
        abstract: true,
        templateUrl: 'messages/list.html',
        controller: 'MessagesListCtrl as controller',
        resolve: {
            'conversations': function(Restangular) {
                return Restangular.all('conversations').getList();
            }
        }
    });

    $stateProvider.state('messages.list', {
        url: '/messages',
        templateUrl: 'messages/conversation.html',
        controller: 'MessagesDetailCtrl as controller',
        resolve: {
            'conversation': function(conversations) {
                var lastId = _.last(_.sortBy(conversations, 'lastwrite')).id;
                conversations.selectedId = lastId;

                return conversations.get(lastId);
            }
        }
    });

    $stateProvider.state('messages.detail', {
        url: '/messages/{conversationId:[0-9]{1,8}}',
        templateUrl: 'messages/conversation.html',
        controller: 'MessagesDetailCtrl as controller',
        resolve: {
            'conversation': function(conversations) {
                conversations.selectedId = $stateParams.conversationId;

                return conversations.get($stateParams.conversationId);
            }
        }
    });
});

Basically messages.list and messages.detail show the exact same template and use the same controller. The resolve is just a bit different. I'm keeping track of the selectedId on conversations so I can mark the active conversation in the list.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top