23

I'm using the excellent ui-router module in my application. As part of this, I'm using named views to manage the 'dynamic sub-navigation' I have in the app.

Consider the following:

$urlRouterProvider.otherwise('/person/list');

$stateProvider
    .state('person', {
        url: '/person',
        abstract: true,
    })
    .state('person.list', {
        url: '/list',
        views: {
            "main@": {
                templateUrl: "person.list.html",
                controller: 'PersonListController'
            }
        }
    })
    .state('person.details', {
        url: '/{id}',
        views: {
            'main@': {
                templateUrl: "person.details.html",
                controller: 'PersonController'
            },
            'nav@': {
                templateUrl: "person.nav.html",
                controller: 'PersonNavController'
            }
        }
    });

When users first visit the app, they are presented with a list of people. When they click on a person, they are taken to the details page. Pretty basic stuff. Here's the markup if it helps...

<div>
    <aside ui-view="nav"></aside>
    <div ui-view="main"></div>
</div>

However, the PersonNavController calls a REST service to get a list of people, so when viewing a person, the user is able to navigate sibling elements. Using the method above causes the template and controller to re-render, thus causing a delay after every click, despite the content never changing.

Is there a way to keep the 'nav@' view loaded, and only refresh the 'main@' view?

Kieren Johnstone
  • 41,277
  • 16
  • 94
  • 144
mortware
  • 1,910
  • 1
  • 20
  • 35

1 Answers1

25

The way I am using ui-router in this scenarios is: move the views to the least common denominator.

Other words: In case that ui-view="nav" is shared among all the details and is the same for all of them (because it should be loaded only once) - it should be part of the list state (parent of the detail state)

the parent state defintion would be adjusted like this:

.state('person.list', {
    url: '/list',
    views: {
        "main@": {
            templateUrl: "person.list.html",
            controller: 'PersonListController'
        }
        // here we target the person.list.html
        // and its ui-view="nav"
        'nav@person.list': {
            templateUrl: "person.nav.html",
            controller: 'PersonNavController'
        }
    }

So where is the trick? In the power of the angular ui-router. We can, during each state defintion, target the current view. Now, the nav view is part of the list state definition - i.e. it will not be reloaded during the detail switching (also check here for more explanation)

We just have to use the defined naming conventions, see:

Few cited lines from the mentioned documentation:

views: {
    ////////////////////////////////////
    // Relative Targeting             //
    // Targets parent state ui-view's //
    ////////////////////////////////////

    // Relatively targets the 'detail' view in this state's parent state, 'contacts'.
    // <div ui-view='detail'/> within contacts.html
    "detail" : { },            

    // Relatively targets the unnamed view in this state's parent state, 'contacts'.
    // <div ui-view/> within contacts.html
    "" : { }, 

    ///////////////////////////////////////////////////////
    // Absolute Targeting using '@'                      //
    // Targets any view within this state or an ancestor //
    ///////////////////////////////////////////////////////

    // Absolutely targets the 'info' view in this state, 'contacts.detail'.
    // <div ui-view='info'/> within contacts.detail.html
    "info@contacts.detail" : { }

    // Absolutely targets the 'detail' view in the 'contacts' state.
    // <div ui-view='detail'/> within contacts.html
    "detail@contacts" : { }
Community
  • 1
  • 1
Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • Why the down vote? I'd like to know what is wrong, to be able to improve the answer... Do not hesitate to leave a comment. – Radim Köhler Nov 27 '14 at 09:18
  • 1
    This is a great answer, it basically solves the problem which was a reason to create functionalities like 'sticky states' https://github.com/christopherthielen/ui-router-extras and similar – wiherek Jan 29 '15 at 17:22
  • @RadimKöhler I found your answer an excellent one and just upvoted it, although I couldn't get what I could understand of it to work in my similar use case. Could you update it with the other state's (person.details) code as well, please? – lucasnadalutti Jun 15 '15 at 15:45
  • @lucasnadalutti, if you have a question, let me know *(provide a link to it)*, I can check it and try to assist... If you can create a plunker... even broken, I could try to help to make it working. Would this work for you? – Radim Köhler Jun 15 '15 at 17:14
  • 1
    Hi @RadimKöhler, thanks for your answer. I eventually managed to get it to work. Thanks again for your kindness! :) – lucasnadalutti Jun 15 '15 at 17:16
  • 1
    @wiherek how does this solve the problem of sticky states? If I have sbleft, sbright and "", how can I make sure that sbright is never reloaded on route change using relative views? Let's say sbright contains a websocket connection for messages and I'd like to avoid reloading it because it would initiate a new websocket connection on each route change, can I do it using relative routes? –  Aug 19 '15 at 13:41
  • How do you preview `person.list` view from reloading the second time you return to it? – Yiling Feb 20 '16 at 10:31
  • This was answered over a year ago. It seems like what I'm looking for. I have a "list" of categories, a view showing elements within a category (exactly like the problem described here) and I have a third view with the details of the element clicked/selected (in second view). Is it the same principle? I make the "detail" view the main and derive the others from it? Thanks – Nelson Rodriguez May 12 '16 at 18:28
  • I had an abstract top level state and had to put shared views into this state. The solution still worked, but had to remove **template: ""** placeholder from the attributes of the state definition. – Azadrum May 23 '17 at 10:33