it-swarm.com.de

Angular-ui.router: URL ohne Ansichtsaktualisierung aktualisieren

Ich habe ein Angular SPA, das eine Vielzahl von Empfehlungslisten und eine Google-Karte mit Standorten enthält, die auf verschiedenen Ausschnitten einiger Restaurantdaten basieren (siehe m.amsterdamfoodie.nl ). Ich möchte, dass jede dieser Listen eine eigene URL hat. Damit Google die verschiedenen Listen durchsuchen kann, verwende ich <a>-Tags für die offcanvas-Navigation.

Derzeit bewirkt das <a>-Tag eine Aktualisierung der Ansicht, die bei der Karte sehr auffällig ist.

  • Ich kann dies mit ng-click und $event.preventDefault() verhindern (siehe Code-Ausschnitte unten), aber dann muss ich ein Mittel implementieren, um die Browser-URL zu aktualisieren.
  • Aber wenn ich Angulars $state oder den Browser history.pushstate des Browsers versuche, löse ich am Ende Zustandsänderungen aus und die Ansicht wird aktualisiert ...!

Meine Frage ist daher wie kann ich ein Modell und die URL aktualisieren, ohne die Ansicht zu aktualisieren? (Siehe auch Angular/UI-Router - Wie kann ich die URL aktualisieren, ohne alles zu aktualisieren? )

Ich habe mit vielen Ansätzen experimentiert und habe derzeit dieses HTML

<a href="criteria/price/1" class="btn btn-default" ng-click="main.action($event)">Budget</a>

Im Controller:

this.action = ($event) ->
    $event.preventDefault()
    params = $event.target.href.match(/criteria\/(.*)\/(.*)$/)

    # seems to cause a view refresh
    # history.pushState({}, "page 2", "criteria/"+params[1]+"/"+params[2]);

    # seems to cause a view refresh
    # $state.transitionTo 'criteria', {criteria:params[1], q:params[2]}, {inherit:false}

    updateModel(...)

Und ich glaube, dass ich den $stateProvider-Code auslöst:

angular.module 'afmnewApp'
.config ($stateProvider) ->
  $stateProvider
  .state 'main',
    url: '/'
    templateUrl: 'app/main/main.html'
    controller: 'MainCtrl'
    controllerAs: 'main'
  .state 'criteria',
    url: '/criteria/:criteria/:q'
    templateUrl: 'app/main/main.html'
    controller: 'MainCtrl'
    controllerAs: 'main'

Ein möglicher Hinweis ist der folgende Code, wenn ich z. http://afmnew.herokuapp.com/criteria/cuisine/italian dann wird die Ansicht aktualisiert, während Sie navigieren, wohingegen beim Laden von http://afmnew.herokuapp.com/ dort sind keine Aktualisierungen, jedoch keine URL-Aktualisierungen. Ich verstehe nicht, warum das überhaupt passiert.

23
Simon H

Basierend auf unseren vorherigen Diskussionen möchte ich Ihnen eine Vorstellung davon geben, wie Sie hier UI-Router verwenden. Ich glaube, ich verstehe Ihre Herausforderung richtig ... Es gibt ein funktionierendes Beispiel . Wenn dies nicht vollständig passt, nehmen Sie es als Inspiration

HAFTUNGSAUSSCHLUSS: Mit einem Plunker konnte ich dies nicht erreichen: http://m.amsterdamfoodie.nl/ , aber das Prinzip sollte in Beispiel Ähnlichem stehen

Es gibt also eine Zustandsdefinition (wir haben nur zwei Zustände)}

  $stateProvider
    .state('main', {
        url: '/',
        views: {
          '@' : {
            templateUrl: 'tpl.layout.html',
            controller: 'MainCtrl',
          },
          '[email protected]' : { templateUrl: 'tpl.right.html',}, 
          '[email protected]' : {
            templateUrl: 'tpl.map.html',
            controller: 'MapCtrl',
          },
          '[email protected]' : {
            templateUrl: 'tpl.list.html',
            controller: 'ListCtrl',
          },
        },
      })
    .state('main.criteria', {
        url: '^/criteria/:criteria/:value',
        views: {
          'map' : {
            templateUrl: 'tpl.map.html',
            controller: 'MapCtrl',
          },
          'list' : {
            templateUrl: 'tpl.list.html',
            controller: 'ListCtrl',
          },
        },
      })
}];

Dies wäre unser Haupt tpl.layout.html

<div>

  <section class="main">

    <section class="map">
      <div ui-view="map"></div>
    </section>

    <section class="list">
      <div ui-view="list"></div>
    </section>

  </section>

  <section class="right">
    <div ui-view="right"></div>
  </section>

</div>

Wie wir sehen können, zielt der Hauptzustand auf diese verschachtelten Ansichten des Hauptzustands: 'viewName @ main', z. '[email protected]'

Auch die Unteransicht main.criteria fügt sich in layout - Ansichten ein. 

Seine URL beginnt mit einem Zeichen ^ (url : '^/criteria/:criteria/:value'), das einen /-Schrägstrich für main und keinen doppelten Schrägstrich für untergeordnetes Element erlaubt

Und es gibt auch Controller, die hier etwas naiv sind, aber sie sollten zeigen, dass im Hintergrund echte Datenlast (basierend auf Kriterien) sein könnte.

Das Wichtigste dabei ist, dass die PARENT MainCtrl den $scope.Model = {} erstellt. Diese Eigenschaft wird (dank der Vererbung) zwischen Eltern und Kindern geteilt. Deshalb funktioniert das alles:

app.controller('MainCtrl', function($scope)
{
  $scope.Model = {};
  $scope.Model.data = ['Rest1', 'Rest2', 'Rest3', 'Rest4', 'Rest5'];  
  $scope.Model.randOrd = function (){ return (Math.round(Math.random())-0.5); };
})
.controller('ListCtrl', function($scope, $stateParams)
{
  $scope.Model.list = []
  $scope.Model.data
    .sort( $scope.Model.randOrd )
    .forEach(function(i) {$scope.Model.list.Push(i + " - " + $stateParams.value || "root")})
  $scope.Model.selected = $scope.Model.list[0];
  $scope.Model.select = function(index){
    $scope.Model.selected = $scope.Model.list[index];  
  }
})

Hier erfahren Sie, wie wir die von UI-Router bereitgestellten Funktionen nutzen können:

Überprüfen Sie den obigen Auszug hier , in das Arbeitsbeispiel

Erweitern: neuer Plunker hier

Wenn die Kartenansicht nicht wiederhergestellt werden soll, können Sie diese Option aus dem untergeordneten Status def weglassen:

.state('main.criteria', {
    url: '^/criteria/:criteria/:value',
    views: {
      // 'map' : {
      //  templateUrl: 'tpl.map.html',
      //  controller: 'MapCtrl',
      //},
      'list' : {
        templateUrl: 'tpl.list.html',
        controller: 'ListCtrl',
      },
    },
  })

Jetzt werden in unserer Kartenansicht lediglich Änderungen im Modell empfangen (können betrachtet werden), aber Ansicht und Controller werden nicht erneut gerendert

Es gibt auch einen anderen Plunker http://plnkr.co/edit/y0GzHv?p=preview , der die controllerAs verwendet.

.state('main', {
    url: '/',
    views: {
      '@' : {
        templateUrl: 'tpl.layout.html',
        controller: 'MainCtrl',
        controllerAs: 'main',        // here
      },
      ...
    },
  })
.state('main.criteria', {
    url: '^/criteria/:criteria/:value',
    views: {
      'list' : {
        templateUrl: 'tpl.list.html',
        controller: 'ListCtrl',
        controllerAs: 'list',      // here
      },
    },
  })

und das könnte so verwendet werden:

<h4>{{main.hello()}}</h4>
<h4>{{list.hello()}}</h4>

Der letzte Plunker ist hier

11
Radim Köhler

Dies ist ein Beispiel für den Weg, wenn ich es richtig verstanden habe:

$state.go('my.state', {id:data.id}, {notify:false, reload:false});
//And to remove the id from the url:
$state.go('my.state', {id:undefined}, {notify:false, reload:false});

Von Benutzer l-liava-l in der Ausgabe https://github.com/angular-ui/ui-router/issues/64

Sie können die $state-API hier überprüfen: http://angular-ui.github.io/ui-router/site/#/api/ui.router.state . $ State

16

sie können die Bereichsvererbung verwenden, um die URL ohne Aktualisierung der Ansicht zu aktualisieren

$stateProvider
            .state('itemList', {
                url: '/itemlist',
                templateUrl: 'Scripts/app/item/ItemListTemplate.html',
                controller: 'ItemListController as itemList'
                //abstract: true //abstract maybe?
            }).state('itemList.itemDetail', {
                url: '/:itemName/:itemID',
                templateUrl: 'Scripts/app/item/ItemDetailTemplate.html',
                controller: 'ItemDetailController as itemDetail',
                resolve: {
                    'CurrentItemID': ['$stateParams',function ($stateParams) {
                        return $stateParams['itemID'];
                    }]
                }
            })

wenn sich die untergeordnete Ansicht in der übergeordneten Ansicht befindet, teilen sich beide Controller denselben Bereich. Sie können also eine Dummy-Ansicht (oder eine erforderliche Ui-Ansicht) in die übergeordnete Ansicht einfügen, die von der untergeordneten Ansicht gefüllt wird.

und füge ein 

$scope.loadChildData = function(itemID){..blabla..};

funktion in der übergeordneten Steuerung, die bei der Controller-Belastung von der untergeordneten Steuerung aufgerufen wird. Wenn also ein Benutzer klickt 

<a ui-sref="childState({itemID: 12})">bla</a> 

nur untergeordnete Controller und untergeordnete Ansichten werden aktualisiert. Dann können Sie die Parent-Scope-Funktion mit den erforderlichen Parametern aufrufen.

2
bahadir

Die kurze Antwort endete mit do not die Karte in eine sich ändernde Ansicht. Die akzeptierte Antwort enthält viel detailliertere Informationen zum Strukturieren einer Seite mit Unteransichten. Der Schlüsselpunkt ist jedoch nicht, die Karte in die Ansicht aufzunehmen, sondern ihr Verhalten mit einer Ansicht zu verknüpfen, die sich ändert, und einen Controller zu verwenden Aktualisieren Sie die Marktsymbole.

0
Simon H