Angular-UI 路由器:嵌套视图不起作用 [英] Angular-UI Router: Nested Views Not Working

查看:42
本文介绍了Angular-UI 路由器:嵌套视图不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

构建多步骤表单(向导").最初关注 本教程,效果很好,但现在我正在尝试适应所以第一步是嵌入在主页上,而不是一个单独的状态.无论我尝试什么,我都无法创建一个有效的 ui-sref 路径.我总是得到:

<块引用>

无法从状态home"解析.where"

<块引用>

无法从状态home"解析wizard.where"

<块引用>

无法从状态 'home' 解析 'wizard.where@'

...即使 wizard.where@<div ui-view="wizard.where@"></div> 中工作正常.什么是正确的语法?

以下是相关文件:

home.js(保留注释不变,以便您可以看到我尝试的各种方法):

var 向导 = {url: '/home/wizard',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard.tpl.html'};angular.module('myApp.home', ['ui.router','ui.bootstrap','myApp.modal','角时刻']).config(function config( $stateProvider, $urlRouterProvider ) {$stateProvider.state('家', {网址:'/家',意见:{主要的": {控制器:'HomeCtrl',templateUrl: 'home/home.tpl.html'},大屏幕":{控制器:'HomeCtrl',templateUrl: 'home/welcome.tpl.html'},向导":向导,向导.在哪里":{url: '/home/wizard/where',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-where.tpl.html',家长:巫师},向导.什么":{url: '/home/wizard/what',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-what.tpl.html',家长:巫师},wizard.when":{url: '/home/wizard/when',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-when.tpl.html',家长:巫师},},数据:{ pageTitle:'首页'}})//路由显示我们的基本表单(/wizard)//.state('向导', {//url: '/wizard',//视图:{//    主要的": {//控制器: 'VendorsCtrl',//templateUrl: 'vendors/wizard.tpl.html'//}//},//摘要:真,////data: { pageTitle: '供应商搜索' }//})//嵌套状态//每个部分都有自己的视图//url 将被嵌套 (/wizard/where)//.state('wizard.where', {//url: '/where',//templateUrl: 'vendors/wizard-where.tpl.html'//})//url 将是/wizard/when//.state('wizard.when', {//url: '/when',//templateUrl: 'vendors/wizard-when.tpl.html'//})//url 将是/wizard/vendor-types//.state('wizard.what', {//url: '/what',//templateUrl: 'vendors/wizard-what.tpl.html'//});//捕获所有路由//将用户发送到表单页面$urlRouterProvider.otherwise('/home/wizard/where');})

wizard.tpl.html:

<header class="page-title"><h1>{{ pageTitle }}</h1><p>回答以下三个问题以搜索可用的供应商.以后可以更改所有答案.</p><!-- 使用相对路径指向嵌套状态的链接--><!-- 如果状态与我们的 ui-sref 匹配,则添加活动类 --><div id="status-buttons" class="text-center"><a ui-sref-active="active" ui-sref="wizard.where@"><span>1</span>其中</a><a ui-sref-active="active" ui-sref="wizard.what@"><span>2</span>什么</a><a ui-sref-active="active" ui-sref="wizard.when@"><span>3</span>当</a>

</标题><!-- 使用 ng-submit 来捕获表单提交并使用我们的 Angular 函数 --><form id="signup-form" ng-submit="processForm()"><!-- 我们的嵌套状态视图将在这里注入--><div id="form-views" ui-view="wizard.where@"></div></表单>

wizard.where.tpl.html:

<label class="h2" for="where">你的婚礼在哪里?</label><p id="vendor-where-description">如果留空,将显示所有可用位置的供应商.</p><div class="input-group-lg"><input id="where" ng-model="formData.where" class="form-control" type="text" placeholder="Boston, MA" aria-describeby="vendor-where-description"/>

<ul class="list-inline"><li><a ui-sref="wizard.what@" class="btn btn-block btn-primary">接下来<span class="fa fa-arrow-right"></span></a>

解决方案

我在这里创建了工作plunker

注意:您应该更多地了解状态嵌套和命名视图.因为当前状态和视图定义完全错误.

首先,我们不应将 ONE 状态定义用于许多 视图:{}.但是我们应该将它们分成真实的状态.层次结构将具有三个级别

第一级——超级根状态

.state( 'home', {网址:'/家',意见:{主要的": {控制器:'HomeCtrl',templateUrl: 'home/home.tpl.html'},}})

第二级 - wizzard,检查现在我们更改了 url.我们将从我们的父母(家)那里继承它的第一部分

.state("向导", {父母:'家',//url: '/home/wizard',网址:'/向导',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard.tpl.html'})

第三层——所有where、what、when now 也会继承url.他们不必定义父级,因为它是他们名字的一部分

.state( "wizard.where", {//url: '/home/wizard/where',网址:'/哪里',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-where.tpl.html',//父:向导}).state("wizard.what", {//url: '/home/wizard/what',网址:'/什么',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-what.tpl.html',//父:向导}).state("wizard.when", {//url: '/home/wizard/when',网址:'/当',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-when.tpl.html',//父:向导})

向导现在必须包含未命名的视图目标ui-view=""

<div ui-view=""></div>

当前 wizard.tpl.html 包含以下内容:

<!-- 我们的嵌套状态视图将在这里注入--><div id="form-views" ui-view="wizard.where@"></div>

应该避免使用符号 @,因为它可以用于绝对视图命名 - 但在状态定义内部.所以,什么是可行的 ui-view="someName

<!-- 我们的嵌套状态视图将在这里注入--><div id="form-views" ui-view="someName"></div>

现在,这些是(示例中)home.tpl

<h1>家</h1><div ui-view=""></div>

wizzard.tpl

<h2>向导</h2><div ui-view=""></div>

所以,我们在 homewizard 状态中有未命名的视图目标,这非常方便,因为我们可以使用光状态定义,而无需 <代码>视图:{} 对象.如果我们没有多视图,这总是首选.

这意味着,这个状态定义将被正确地注入到上面的模板中:

//没有视图 - 在父视图中搜索 ui-view=""....state("wizard.when", {网址:'/当',控制器:'VendorsCtrl',templateUrl: 'vendors/wizard-when.tpl.html',})...

检查文档:

查看名称 - 相对名称与绝对名称

<块引用>

在幕后,每个视图都被分配一个绝对名称,遵循 viewname@statename 方案,其中 viewname 是视图指令和状态名称中使用的名称是状态的绝对名称,例如联系方式.您还可以选择以绝对语法编写视图名称.

例如,前面的例子也可以写成:

.state('报告',{意见:{'过滤器@':{},'表数据@':{},'图@':{}}})

<块引用>

请注意,视图名称现在指定为绝对名称,而不是相对名称.它针对位于根未命名模板中的过滤器"、表数据"和图形"视图.由于它未命名,因此@"后面没有任何内容.根未命名模板是您的 index.html.

从状态调用状态

如果我们想在where状态导航到when,我们可以使用directiv ui-sref,但必须包含状态名,而不是视图命名约定

//而不是这个<a ui-sref="wizard.what@"我们需要这个<a ui-sref="wizard.what"

在这个三级层次结构中我们只使用父名和子名(不是祖父'home')的原因隐藏在状态定义中.因为我们用过这个:

.state("向导", {父母:'家',

Parent 只是一个父级,而不是州名的一部分.这在这样的场景中很好(我们需要根/祖父来建立一些共同的东西,但子状态不需要它的名字)

检查文档:

ui-sref

<块引用>

将链接( 标记)绑定到状态的指令.如果状态具有关联的 URL,则该指令将自动生成 &通过 $state.href() 方法更新 href 属性.单击该链接将触发带有可选参数的状态转换.
...

您可以使用 ui-sref-opts 属性指定要传递给 $state.go() 的选项.选项仅限于定位、继承和重新加载.

ui-sref - 字符串 - 'stateName' 可以是任何有效的绝对或相对状态

Building a multi-step form ("wizard"). Was originally following this tutorial, which worked great, but am now trying to adapt it so step one is embedded on the homepage rather than being a separate state. No matter what I try, I can not create a ui-sref path that will work. I always get:

Could not resolve '.where' from state 'home'

or

Could not resolve 'wizard.where' from state 'home'

or

Could not resolve 'wizard.where@' from state 'home'

…even though wizard.where@ works fine in <div ui-view="wizard.where@"></div>. What is the correct syntax?

Here are the relevant files:

home.js (left comments intact so you can see various methods I’m trying):

var wizard = {
  url: '/home/wizard',
  controller: 'VendorsCtrl',
  templateUrl: 'vendors/wizard.tpl.html'
};

angular.module( 'myApp.home', [
  'ui.router',
  'ui.bootstrap',
  'myApp.modal',
  'angularMoment'
])

.config(function config( $stateProvider, $urlRouterProvider ) {
  $stateProvider
    .state( 'home', {
      url: '/home',
      views: {
        "main": {
          controller: 'HomeCtrl',
          templateUrl: 'home/home.tpl.html'
        },
        "jumbotron": {
          controller: 'HomeCtrl',
          templateUrl: 'home/welcome.tpl.html'
        },
        "wizard": wizard,
        "wizard.where": {
          url: '/home/wizard/where',
          controller: 'VendorsCtrl',
          templateUrl: 'vendors/wizard-where.tpl.html',
          parent: wizard
        },
        "wizard.what": {
          url: '/home/wizard/what',
          controller: 'VendorsCtrl',
          templateUrl: 'vendors/wizard-what.tpl.html',
          parent: wizard
        },
        "wizard.when": {
          url: '/home/wizard/when',
          controller: 'VendorsCtrl',
          templateUrl: 'vendors/wizard-when.tpl.html',
          parent: wizard
        },
      },
      data: { pageTitle: 'Home' }
    })

    // route to show our basic form (/wizard)
    // .state('wizard', {
    //   url: '/wizard',
    //   views: {
    //     "main": {
    //       controller: 'VendorsCtrl',
    //       templateUrl: 'vendors/wizard.tpl.html'
    //     }
    //   },
    //   abstract: true,
    //   //data: { pageTitle: 'Vendor Search' }
    // })

    // nested states 
    // each of these sections will have their own view
    // url will be nested (/wizard/where)
    // .state('wizard.where', {
    //   url: '/where',
    //   templateUrl: 'vendors/wizard-where.tpl.html'
    // })

    // url will be /wizard/when
    // .state('wizard.when', {
    //   url: '/when',
    //   templateUrl: 'vendors/wizard-when.tpl.html'
    // })

    // url will be /wizard/vendor-types
    // .state('wizard.what', {
    //   url: '/what',
    //   templateUrl: 'vendors/wizard-what.tpl.html'
    // })
    ;

    // catch all route
    // send users to the form page 
    $urlRouterProvider.otherwise('/home/wizard/where');
})

wizard.tpl.html:

<div class="jumbotron vendate-wizard" ng-controller="VendorsCtrl as vendorsCtrl">
  <header class="page-title">
    <h1>{{ pageTitle }}</h1>
    <p>Answer the following three questions to search available vendors. All answers can be changed later.</p>

    <!-- the links to our nested states using relative paths -->
    <!-- add the active class if the state matches our ui-sref -->
    <div id="status-buttons" class="text-center">
      <a ui-sref-active="active" ui-sref="wizard.where@"><span>1</span> Where</a>
      <a ui-sref-active="active" ui-sref="wizard.what@"><span>2</span> What</a>
      <a ui-sref-active="active" ui-sref="wizard.when@"><span>3</span> When</a>
    </div>
  </header>

  <!-- use ng-submit to catch the form submission and use our Angular function -->
  <form id="signup-form" ng-submit="processForm()">

    <!-- our nested state views will be injected here -->
    <div id="form-views" ui-view="wizard.where@"></div>
  </form>
</div>

wizard.where.tpl.html:

<div class="form-group">
  <label class="h2" for="where">Where Is Your Wedding?</label>
  <p id="vendor-where-description">If left blank, vendors in all available locations will be shown.</p>
  <div class="input-group-lg">
    <input id="where" ng-model="formData.where" class="form-control" type="text" placeholder="Boston, MA" aria-describedby="vendor-where-description" />
  </div>
</div>

<ul class="list-inline">
  <li>
    <a ui-sref="wizard.what@" class="btn btn-block btn-primary">
      Next <span class="fa fa-arrow-right"></span>
    </a>
  </li>
</ul>

解决方案

I created working plunker here

NOTE: You should read about state nesting and named views more. Because the current state and view definition is simply wrong.

Firstly, we should not use the ONE state definition with many views: {}. But we should split them into real states. Hierarchy will have three levels

The first level - super root state

.state( 'home', {
  url: '/home',
  views: {
    "main": {
      controller: 'HomeCtrl',
      templateUrl: 'home/home.tpl.html'
    },
  }
})

The second level - wizzard, check that now we change the url. We will inherit its first part from our parent (home)

.state("wizard", {
  parent: 'home',
  //url: '/home/wizard',
  url: '/wizard',
  controller: 'VendorsCtrl',
  templateUrl: 'vendors/wizard.tpl.html'
})

The third level - all where, what, when now will also inherit url. They do not have to define parent, because it is part of their names

.state( "wizard.where",  {
      //url: '/home/wizard/where',
      url: '/where',
      controller: 'VendorsCtrl',
      templateUrl: 'vendors/wizard-where.tpl.html',
      //parent: wizard
})
.state( "wizard.what",  {
      //url: '/home/wizard/what',
      url: '/what',
      controller: 'VendorsCtrl',
      templateUrl: 'vendors/wizard-what.tpl.html',
      //parent: wizard
})
.state( "wizard.when",  {
      //url: '/home/wizard/when',
      url: '/when',
      controller: 'VendorsCtrl',
      templateUrl: 'vendors/wizard-when.tpl.html',
      //parent: wizard
})

Parent wizzard must now contain unnamed view target ui-view=""

<div ui-view=""></div>

Current wizard.tpl.html contains this:

<!-- our nested state views will be injected here -->
<div id="form-views" ui-view="wizard.where@"></div>

The sign @ should be avoided, because it could be used for absulte view naming - BUT inside of the state defintion. So, what could work is ui-view="someName

<!-- our nested state views will be injected here -->
<div id="form-views" ui-view="someName"></div>

Now, these are (in example here) view content of the home.tpl

<div>
  <h1>HOME</h1>

  <div ui-view=""></div>
</div>

And wizzard.tpl

<div>
  <h2>WIZZARD</h2>

  <div ui-view=""></div>
</div>

So, we have unnamed view target inside of home and wizard states, That is very handy, because we can use the light state definition, without views : {} object. And that is always preferred in case we do not have multi-views.

That means, that this state definition will properly be injected into above template:

// no views - search in parent for a ui-view=""
...
.state( "wizard.when",  {
      url: '/when',
      controller: 'VendorsCtrl',
      templateUrl: 'vendors/wizard-when.tpl.html',
})
...

Check the doc:

View Names - Relative vs. Absolute Names

Behind the scenes, every view gets assigned an absolute name that follows a scheme of viewname@statename, where viewname is the name used in the view directive and state name is the state's absolute name, e.g. contact.item. You can also choose to write your view names in the absolute syntax.

For example, the previous example could also be written as:

.state('report',{
    views: {
      'filters@': { },
      'tabledata@': { },
      'graph@': { }
    }
})

Notice that the view names are now specified as absolute names, as opposed to the relative name. It is targeting the 'filters', 'tabledata', and 'graph' views located in the root unnamed template. Since it's unnamed, there is nothing following the '@'. The root unnamed template is your index.html.

Calling the state from state

Whe we want in where state navigate to when, we can use directiv ui-sref, but it must contain state name, not view naming convention

// instead of this
<a ui-sref="wizard.what@"
we need this
<a ui-sref="wizard.what"

The reason, that in this three level hierarchy we do use only parent and child names (not grand parent 'home'), is hidden in state definition. Because we used this:

.state("wizard", {
  parent: 'home',

Parent is just a parent, not part of the state name. Which is good in scenarios like this (we need the root/grand parent to establish some comon stuff, but it name is not needed for substates)

Check the doc:

ui-sref

A directive that binds a link (<a> tag) to a state. If the state has an associated URL, the directive will automatically generate & update the href attribute via the $state.href() method. Clicking the link will trigger a state transition with optional parameters.
...

You can specify options to pass to $state.go() using the ui-sref-opts attribute. Options are restricted to location, inherit, and reload.

ui-sref - string - 'stateName' can be any valid absolute or relative state

这篇关于Angular-UI 路由器:嵌套视图不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆