wake-up-neo.com

Angular-UI-Router: Verschachtelte Ansichten funktionieren nicht

Erstellen eines mehrstufigen Formulars ("Assistent"). Hat ursprünglich dieses Tutorial gefolgt, was sehr gut funktioniert hat, aber ich versuche jetzt, es so anzupassen, dass Schritt 1 auf der Homepage eingebettet ist, anstatt ein separater Status zu sein. Egal was ich versuche, ich kann keinen ui-sref - Pfad erstellen, der funktioniert. Ich bekomme immer:

Konnte ".where" nicht von "Heimat" aus auflösen

oder

'Wizard.where' konnte vom Status 'home' nicht aufgelöst werden

oder

'Wizard.where @' konnte im Status 'home' nicht aufgelöst werden

… Obwohl [email protected] In <div ui-view="[email protected]"></div> Gut funktioniert. Was ist die richtige Syntax?

Hier sind die relevanten Dateien:

home.js (Kommentare intakt gelassen, damit Sie verschiedene Methoden sehen können, die ich versuche):

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>
14
Hugh Guiney

Ich schuf arbeitender Plunker hier

HINWEIS: Sie sollten mehr über Statusverschachtelung und benannte Ansichten lesen. Weil der aktuelle Status und die Ansichtsdefinition einfach falsch sind.

Erstens sollten wir nicht die [~ # ~] eine [~ # ~] Zustandsdefinition mit vielen views: {}. Aber wir sollten sie in reale Zustände aufteilen. Hierarchie wird drei Ebenen haben

Die erste Ebene - Super-Root-Status

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

Die zweite Ebene - Wizzard, überprüfen Sie, ob wir jetzt die URL ändern. Wir werden seinen ersten Teil von unseren Eltern (zu Hause) erben

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

Die dritte Ebene - alle, wo, was, wann wird jetzt auch URL erben. Sie müssen kein übergeordnetes Element definieren, da es Teil ihres Namens ist

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

Der übergeordnete Assistent muss jetzt ein unbenanntes Ansichtsziel enthalten ui-view=""

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

Die aktuelle wizard.tpl.html enthält Folgendes:

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

Das Vorzeichen @ sollte vermieden werden, da es für die Benennung von Absulte-Views verwendet werden kann - ABER innerhalb der Zustandsdefinition. Was also funktionieren könnte ist ui-view="someName

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

Dies sind nun ( im Beispiel hier ) Ansichtsinhalte des home.tpl

<div>
  <h1>HOME</h1>

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

Und wizzard.tpl

<div>
  <h2>WIZZARD</h2>

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

Wir haben also ein unbenanntes Ansichtsziel innerhalb der Zustände home und Wizard . Das ist sehr praktisch, da wir die Lichtzustandsdefinition ohne views : {} Objekt verwenden können. Und das ist immer dann vorzuziehen, wenn wir keine Mehrfachansichten haben.

Das bedeutet, dass diese Zustandsdefinition korrekt in die obige Vorlage eingefügt wird:

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

Überprüfen Sie das Dokument:

Namen anzeigen - Relative vs. Absolute Namen

Hinter den Kulissen wird jeder Ansicht ein absoluter Name zugewiesen, der dem Schema [email protected] folgt, wobei viewname der in der Ansicht verwendete Name ist richtlinie und staatsname ist der absolute name des staats, zb contact.item. Sie können Ihre Ansichtsnamen auch in der absoluten Syntax schreiben.

Das vorherige Beispiel könnte zum Beispiel auch so geschrieben werden:

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

Beachten Sie, dass die Ansichtsnamen im Gegensatz zum relativen Namen jetzt als absolute Namen angegeben werden. Es zielt auf die Ansichten 'filters', 'tabledata' und 'graph' ab, die sich in der unbenannten Stammvorlage befinden. Da es unbenannt ist, folgt dem '@' nichts. Die unbenannte Stammvorlage ist Ihre index.html.

Aufruf des Staates vom Staat

Wenn wir möchten, wohin der Status navigiert, können wir directiv ui-sref Verwenden, aber es muss den Namen des Status enthalten, nicht die Namenskonvention für die Ansicht

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

Der Grund dafür, dass in dieser Hierarchie mit drei Ebenen nur Eltern- und Kindernamen verwendet werden (nicht 'zu Hause' der Großeltern, ist in der Zustandsdefinition verborgen. Weil wir das benutzt haben:

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

Elternteil ist nur ein Elternteil, nicht Teil des Zustandsnamens. Was in solchen Szenarien gut ist (wir brauchen die Wurzel/den Großelternteil, um ein paar gemeinsame Dinge zu etablieren, aber der Name wird für Unterstaaten nicht benötigt)

Überprüfen Sie das Dokument:

i-sref

Eine Direktive, die einen Link (<a> - Tag) an einen Zustand bindet. Wenn dem Status eine URL zugeordnet ist, generiert und aktualisiert die Direktive das href-Attribut automatisch über die $ state.href () -Methode. Durch Klicken auf den Link wird ein Statusübergang mit optionalen Parametern ausgelöst.
...

Sie können Optionen angeben, die an $ state.go () übergeben werden sollen, indem Sie das Attribut ui-sref-opts Verwenden. Die Optionen sind auf Speicherort, Erben und Neuladen beschränkt.

ui-sref - string - 'stateName' kann sein Jeder gültige absolute oder relative Zustand

42
Radim Köhler

[S] tep one ist auf der Startseite eingebettet und kein separater Status

Sie sollten jede UI-Ansicht als Status behandeln, aber wizard.where Als Standard-/Indexstatus deklarieren.

Beachten Sie, dass das Lernprogramm $ urlRouterProvider verwendet, um form/profile Zum Standardstatus zu machen.

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

Auf diese Weise erhält /form Jedoch den Wert /form/profile.

Sie können jedoch einen leeren URL-Status mit geringfügige Änderung erstellen:

// 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 hat auch großartige Einblicke in UI-Router und Zustandsdefinitionen geliefert.

3
SirTophamHatt