Подтвердить что ты не робот

Angular -UI Router: вложенные представления не работают

Создание многоступенчатой ​​формы ( "мастер" ). Первоначально был из этого учебника, который отлично поработал, но теперь я пытаюсь его адаптировать, поэтому первый шаг встроен на домашнюю страницу, а не в отдельное состояние. Независимо от того, что я пытаюсь, я не могу создать путь ui-sref, который будет работать. Я всегда получаю:

Не удалось разрешить ".where" из состояния "home"

или

Не удалось разрешить "wizard.where" из состояния "home"

или

Не удалось разрешить "wizard.where @" из состояния "home"

... хотя [email protected] отлично работает в <div ui-view="[email protected]"></div>. Каков правильный синтаксис?

Вот соответствующие файлы:

home.js (левые комментарии нетронуты, поэтому вы можете увидеть различные методы Im try):

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="[email protected]"><span>1</span> Where</a>
      <a ui-sref-active="active" ui-sref="[email protected]"><span>2</span> What</a>
      <a ui-sref-active="active" ui-sref="[email protected]"><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="[email protected]"></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="[email protected]" class="btn btn-block btn-primary">
      Next <span class="fa fa-arrow-right"></span>
    </a>
  </li>
</ul>
4b9b3361

Ответ 1

Я создал рабочий плункер здесь

ПРИМЕЧАНИЕ. Вы должны больше узнать о состоянии вложенности и названии. Потому что текущее состояние и определение представления просто неверны.

Во-первых, мы не должны использовать определение состояния ONE со многими views: {}. Но мы должны разделить их на реальные состояния. Иерархия будет иметь три уровня

Первый уровень - состояние супер-root

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

Второй уровень - wizzard, убедитесь, что теперь мы меняем URL-адрес. Мы наследуем его первую часть от нашего родителя (дома)

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

Третий уровень - все где, что, когда теперь также наследует url. Они не должны определять родителя, потому что это часть их имен

.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
})

Родительский wizzard должен теперь содержать неименованный целевой объект ui-view=""

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

Текущий wizard.tpl.html содержит следующее:

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

Знак @ следует избегать, поскольку он может использоваться для наименования абсурдного представления - НО внутри определения состояния. Итак, что может работать ui-view="someName

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

Теперь, это (в примере здесь) просмотрите содержимое home.tpl

<div>
  <h1>HOME</h1>

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

И wizzard.tpl

<div>
  <h2>WIZZARD</h2>

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

Итак, у нас есть неназванная цель представления внутри home и wizard, это очень удобно, потому что мы можем использовать определение состояния света без views : {}. И это всегда предпочтительнее, если у нас нет мульти-просмотров.

Это означает, что это определение состояния будет правильно введено в шаблон:

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

Проверьте документ:

Просмотреть имена - Относительные и абсолютные имена

За кулисами каждому представлению присваивается абсолютное имя, которое следует схеме [email protected], где viewname - это имя, используемое в директиве представления, а имя состояния - это абсолютное имя состояния, например. contact.item. Вы также можете написать имена имен в абсолютном синтаксисе.

Например, предыдущий пример также можно было записать как:

.state('report',{
    views: {
      '[email protected]': { },
      '[email protected]': { },
      '[email protected]': { }
    }
})

Обратите внимание, что имена представлений теперь указаны как абсолютные имена, а не относительное имя. Он нацелен на представления "фильтры", "tabledata" и "graph", расположенные в корневом неназванном шаблоне. Поскольку он не указан, ничего не следует за "@". Корневой неназванный шаблон - ваш index.html.

Вызов состояния из состояния

Мы хотим, чтобы в том случае, когда состояние переходит к тому, когда мы можем использовать directiv ui-sref, но он должен содержать имя состояния, а не просмотр соглашения об именах

// instead of this
<a ui-sref="[email protected]"
we need this
<a ui-sref="wizard.what"

Причина того, что в этой трехуровневой иерархии мы используем только родительские и дочерние имена (не grand parent 'home'), скрыты в определении состояния. Потому что мы использовали это:

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

Родитель является родителем, а не частью имени состояния. Что хорошо в таких сценариях (нам нужен корень/великий родитель, чтобы установить некоторые компоненты comon, но это имя не требуется для подстанций)

Проверьте документ:

ui-sref

Директива, которая связывает ссылку (тег <a>) с состоянием. Если у государства есть связанный URL, директива автоматически генерирует и обновляет атрибут href с помощью метода $state.href(). Щелчок по ссылке вызовет переход состояния с дополнительными параметрами.
...

Вы можете указать параметры для перехода к $state.go() с помощью атрибута ui-sref-opts. Параметры ограничены местоположением, наследованием и перезагрузкой.

ui-sref - строка - 'stateName' может быть любым действительным абсолютным или относительным состоянием

Ответ 2

[S] tep one встроен на домашнюю страницу, а не является отдельным состоянием

Вы должны рассматривать каждый ui-view как состояние, но объявляйте wizard.where как состояние по умолчанию/индексу.

Обратите внимание, что в учебнике используется $urlRouterProvider, чтобы сделать form/profile состояние по умолчанию.

// catch all route
// send users to the form page 
$urlRouterProvider.otherwise('/form/profile');

Таким образом, /form закончится как /form/profile.

Однако вы можете создать пустое состояние URL с незначительные изменения:

// route to show our basic form (/form)
.state('form', {
    url: '/form',
    templateUrl: 'form.html',
    controller: 'formController',
    abstract: true //<-- Declare parent as an abstract state. 
})

// nested states 
// each of these sections will have their own view
// url will be nested (/form)
.state('form.profile', {
    url: '', //<-- Empty string for "profile" state to override the /form abstract state
    templateUrl: 'form-profile.html'
})

// catch all route
// send users to the form page
$urlRouterProvider.otherwise('/form'); //<-- Default state is empty

@radim-köhler также предоставил большое представление о UI-Router и определениях состояний.