How can I persist sibling ui-views when changing state?

孤者浪人 提交于 2019-12-30 11:35:44

问题


I have 2 ui-view directives in my application. One contains subnavigation and the other is the actual page content. My subnavigation is a tree structure, and when you click on an end node (or a leaf) should be the only time the content view gets updated. Whenever you click non-leaf nodes in the subnavigation, I would like the content view to stay the same while the subnavigation view changes.

What is happening is whenever I switch to a state that does not define one of the views, the view gets cleared out. I want it to stay how it was previous to me changing state. Has anyone accomplished this?

Code:

<!--NOTE THAT THESE ARE SIBLING ELEMENTS, NOT NESTED -->
<div id="subNav" ui-view="subNav"></div>
<div id="content" ui-view="content"></div>

Here is my route setup. Note that State1 only should update the subnav view and State2 should only update the content view.

$stateProvider
  .state('State1', {
    url: '/State1',
    views: {
      "subnav": { 
         templateUrl: "views/subnav.html",
         controller: "SubNavController"
      }
    }
  })
  .state('State2', {
    url: '/State2',
    views: {
      "content": { 
         template: "<p>State 2</p>"
      }
    }
  });

Here is a plnkr of what is is currently doing: http://plnkr.co/edit/TF7x5spB8zFLQPzrgZc9?p=preview


回答1:


I would say, that the way to go here is really very clear:

Multiple Named Views

Nested States & Nested Views

I am using this technique, in very similar scenario: left column is a list, right (large area) is a place for a detail. There is an example

The state def would be:

$stateProvider
    .state('index', {
        url: '/',
        views: {
          '@' : {
            templateUrl: 'layout.html',
            controller: 'IndexCtrl'
          },
          'top@index' : { templateUrl: 'tpl.top.html',},
          'left@index' : { templateUrl: 'tpl.left.html',},
          'main@index' : { templateUrl: 'tpl.main.html',},
        },
      })
    .state('index.list', {
        url: '/list',
        templateUrl: 'list.html',
        controller: 'ListCtrl'
      })
    .state('index.list.detail', {
        url: '/:id',
        views: {
          'detail@index' : {
            templateUrl: 'detail.html',
            controller: 'DetailCtrl'
          },
        },
      })

So in our case, it could be like this:

  1. the parent state would have a template for both states (layout) and also will inject the navbar
  2. the child will just inject the view into main area

the Parent state:

.state('State1', {
    url: '/State1',
    views: {
      "bodyArea" { template: "body.thml"},
      "subnav@State1": { 
         templateUrl: "views/subnav.html",
         controller: "SubNavController"
      }
    }
})

So what we can see, the template for both states, the layout is defined on the State1 as a view placed in "bodyArea".

The other view (original) is injected into that template, via absolute name "subnav@State1". I.e. 2 views defined for one parent state...

The Child state:

.state('State2', {
    parent: 'State1', // a child needs parent
    url: '/State2',
    views: {
      "content": { 
         template: "<p>State 2</p>"
      }
    }
})

Here, we just say, that State1 is parent of State2. That means, that the "content" target/anchor (ui-view="content") must be part of the views defined in State1. The best place here would the "body.html"...

EXTEND: based on comments and this plunker with some issues, I created its updated version. Navigation to Main1 is broken (to be able to compare), but Main2 and Main3 are working.

  • Main2 is working because it has the similar def as index state
  • Main3 is on the other hand child of the index state

The absolute and relative naming in action should be clear from this snippet:

the index:

$stateProvider
  .state('index', {
    url: '/',
    views: {
      '@': {
        templateUrl: 'layout.html'
      },
      'mainNav@index': {
        template: '<a ui-sref="Main1">Main1</a><br />'
                + '<a ui-sref="Main2">Main2</a><br />'
                + '<a ui-sref="Main3">Main3</a>'
      },
      'subNav@index' : {
        template: '<p>This is the sub navigation</p>'
      }, 
      'content@index': {
        template: '<p>This is the content</p>'
      }
    }
  })

the Main1 with issues

  .state('Main1', {
    url: '/Main1',
    views: {
      /*'mainNav': {

      },*/
      'subNav': {
        template: '<a ui-sref="Sub1">Sub1</a><a ui-sref="Sub2">Sub2</a>'
      },
      'content': {
        template: '<p>This is the content in Main1</p>'
      }
    }
  })

working states

  .state('Main2', {
    url: '/Main2',
    views: {
      '': {
        templateUrl: 'layout.html'
      },
      'mainNav@Main2': {
        template: '<a ui-sref="Main1">Main1</a><br />'
                + '<a ui-sref="Main2">Main2</a><br />'
                + '<a ui-sref="Main3">Main3</a>'
      },
      'subNav@Main2': {
        template: '<a ui-sref="Sub1">Sub for Main2</a>'
      },
      'content@Main2': {
        template: '<p>This is the content in Main2</p>'
      }
    }
  })
  .state('Main3', {
    parent: 'index',  // PARENT does the trick
    url: '/Main3',
    views: {
      'subNav': { // PARENT contains the anchor/target - relative name is enough
        template: '<a ui-sref="Sub1">Sub for Main3</a>'
      },
      'content': {
        template: '<p>This is the content in Main3</p>'
      }
    }
  })


来源:https://stackoverflow.com/questions/25815505/how-can-i-persist-sibling-ui-views-when-changing-state

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!