在ui-router中从较低状态覆盖较高状态的布局视图会导致空ui-view

时间:2022-02-26 03:20:43

I'm trying to create a basic layout system using nested states in angular using ui-router.

我正在尝试使用ui-router在角度中使用嵌套状态创建一个基本布局系统。

What I'd like is that any 'sub state' can override the 'layout' partial of the top level state so that different site layouts can be used depending on the area of the site.

我想要的是,任何“子状态”都可以覆盖*状态的“布局”部分,以便根据站点的区域使用不同的站点布局。

Given the following system/server/views/index.html:

给定以下system / server / views / index.html:

<section data-ui-view="layout" ></section>

and two layouts to be interchanged into the above: system/public/views/layouts/standard.html:

以及两个可以互换的布局:system / public / views / layouts / standard.html:

  <div class="navbar navbar-inverse navbar-fixed-top" data-ui-view="header" data-role="navigation"></div>
  <section class="container-fluid">
      <section data-ui-view ></section>
  </section>

system/public/views/layouts/full-width.html:

系统/公/视图/布局/全width.html:

  <div class="navbar navbar-inverse navbar-fixed-top" data-ui-view="header" data-role="navigation"></div>
  <section class="container">
      <section data-ui-view ></section>
  </section>

sample content system/public/views/index.html

样本内容系统/ public / views / index.html

<div>some sample content</div>

and finally the router:

最后是路由器:

function($stateProvider, $urlRouterProvider) {
  // For unmatched routes:
  $urlRouterProvider.otherwise('/');

  // states for my app
  $stateProvider
    .state('root', {
      url: '/',
      abstract: true,
      views: {
        'layout@': {
          templateUrl: 'system/views/layouts/standard.html'
        },
        'header@root': {
          templateUrl: 'system/views/partials/header.html'
        }
      }
    })
    .state('root.home', {
      url: '',
      views: {
        'header@root': {
          templateUrl: 'system/views/partials/header2.html'
        },
        '': {
          templateUrl: 'system/views/index.html'
        }
      }
    });
}

The above works. I'm able to swap the header in and out in the sub states, but if I add the override for the 'layout':

以上工作。我可以在子状态中交换标头,但是如果我为'布局'添加覆盖:

function($stateProvider, $urlRouterProvider) {
  // For unmatched routes:
  $urlRouterProvider.otherwise('/');

  // states for my app
  $stateProvider
    .state('root', {
      url: '/',
      abstract: true,
      views: {
        'layout@': {
          templateUrl: 'system/views/layouts/standard.html'
        },
        'header@root': {
          templateUrl: 'system/views/partials/header.html'
        }
      }
    })
    .state('root.home', {
      url: '',
      views: {
        'header@root': {
          templateUrl: 'system/views/partials/header2.html'
        },
        '': {
          templateUrl: 'system/views/index.html'
        },
--->>> 'layout@': {
          templateUrl: 'system/views/layouts/full-width.html'
        }
      }
    });
}

When I add the 'layout@' the date-ui-view="layout" does get loaded correctly but the sub ui-views for the header and the unamed do not get replaced.

当我添加'layout @'时,date-ui-view =“layout”确实正确加载,但是标题和unamed的子ui-views不会被替换。

Any ideas what is going on here?

有什么想法在这里发生了什么?

If this isn't something that should work what are alternative approaches?

如果这不是可行的东西,那么什么是替代方法?

1 个解决方案

#1


15  

The point is that overriding template in a child state 'root.home' like this:

重点是在子状态'root.home'中覆盖模板,如下所示:

.state('root.home', {
    ...
->> 'layout@': {
      templateUrl: 'system/views/layouts/full-width.html'
    }

Is in fact totally removing any part from the parent 'root'. So now we have to use this for sibling views:

实际上完全从父“root”中删除任何部分。所以现在我们必须将它用于兄弟视图:

    'header@root.home': {  // see the 'root.home' after @
      templateUrl: 'system/views/partials/header2.html'
    },
    '@root.home': {        // see the 'root.home' after @
      templateUrl: 'system/views/index.html'
    },

See, that we used root.home after @. That is: We are explicitly saying:

看,我们在@之后使用了root.home。那就是:我们明确地说:

  • find the ui-view="header" and unnamed ui-view="" inside of this, current 'root.home' state.
  • 在这个当前'root.home'状态中找到ui-view =“header”和未命名的ui-view =“”。

There is no target existing in parent state 'home', because we totally skipped it.

父状态'home'中没有目标存在,因为我们完全跳过它。

The sample in documentation is in this case really self descriptive:

在这种情况下,文档中的示例实际上是自描述的:

View Names - Relative vs. Absolute Names

(cited self describing snippet)

(引用自描述片段)

$stateProvider
  .state('contacts', {
    // This will get automatically plugged into the unnamed ui-view 
    // of the parent state template. Since this is a top level state, 
    // its parent state template is index.html.
    templateUrl: 'contacts.html'   
  })
  .state('contacts.detail', {
    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" : { }

        // Absolutely targets the unnamed view in parent 'contacts' state.
        // <div ui-view/> within contacts.html
        "@contacts" : { }

        // absolutely targets the 'status' view in root unnamed state.
        // <div ui-view='status'/> within index.html
        "status@" : { }

        // absolutely targets the unnamed view in root unnamed state.
        // <div ui-view/> within index.html
        "@" : { } 
  });

Also, please do notice this important fact:

另外,请注意这个重要的事实:

Scope Inheritance by View Hierarchy Only

Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

请记住,只有嵌套状态的视图时,范围属性才会继承状态链。范围属性的继承与状态的嵌套以及与视图(模板)的嵌套有关的所有内容都无关。

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

完全有可能您有嵌套状态,其模板在您站点内的各种非嵌套位置填充ui-views。在这种情况下,您不能期望在子状态的视图中访问父状态视图的范围变量。

I.e. - we cannot inherit from parent 'root' state anyhting, because the inheritance goes only view views...

即 - 我们不能从父'root'状态继承任何东西,因为继承只进行视图查看...

#1


15  

The point is that overriding template in a child state 'root.home' like this:

重点是在子状态'root.home'中覆盖模板,如下所示:

.state('root.home', {
    ...
->> 'layout@': {
      templateUrl: 'system/views/layouts/full-width.html'
    }

Is in fact totally removing any part from the parent 'root'. So now we have to use this for sibling views:

实际上完全从父“root”中删除任何部分。所以现在我们必须将它用于兄弟视图:

    'header@root.home': {  // see the 'root.home' after @
      templateUrl: 'system/views/partials/header2.html'
    },
    '@root.home': {        // see the 'root.home' after @
      templateUrl: 'system/views/index.html'
    },

See, that we used root.home after @. That is: We are explicitly saying:

看,我们在@之后使用了root.home。那就是:我们明确地说:

  • find the ui-view="header" and unnamed ui-view="" inside of this, current 'root.home' state.
  • 在这个当前'root.home'状态中找到ui-view =“header”和未命名的ui-view =“”。

There is no target existing in parent state 'home', because we totally skipped it.

父状态'home'中没有目标存在,因为我们完全跳过它。

The sample in documentation is in this case really self descriptive:

在这种情况下,文档中的示例实际上是自描述的:

View Names - Relative vs. Absolute Names

(cited self describing snippet)

(引用自描述片段)

$stateProvider
  .state('contacts', {
    // This will get automatically plugged into the unnamed ui-view 
    // of the parent state template. Since this is a top level state, 
    // its parent state template is index.html.
    templateUrl: 'contacts.html'   
  })
  .state('contacts.detail', {
    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" : { }

        // Absolutely targets the unnamed view in parent 'contacts' state.
        // <div ui-view/> within contacts.html
        "@contacts" : { }

        // absolutely targets the 'status' view in root unnamed state.
        // <div ui-view='status'/> within index.html
        "status@" : { }

        // absolutely targets the unnamed view in root unnamed state.
        // <div ui-view/> within index.html
        "@" : { } 
  });

Also, please do notice this important fact:

另外,请注意这个重要的事实:

Scope Inheritance by View Hierarchy Only

Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).

请记住,只有嵌套状态的视图时,范围属性才会继承状态链。范围属性的继承与状态的嵌套以及与视图(模板)的嵌套有关的所有内容都无关。

It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.

完全有可能您有嵌套状态,其模板在您站点内的各种非嵌套位置填充ui-views。在这种情况下,您不能期望在子状态的视图中访问父状态视图的范围变量。

I.e. - we cannot inherit from parent 'root' state anyhting, because the inheritance goes only view views...

即 - 我们不能从父'root'状态继承任何东西,因为继承只进行视图查看...