template example angularjs seo angular-ui-router single-page-application

example - ui router angularjs template



Angular-ui.router: Actualizar URL sin actualizaciĆ³n de vista (4)

Este es un ejemplo del camino a seguir si lo entiendo correctamente:

$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});

Del usuario l-liava-l en el problema https://github.com/angular-ui/ui-router/issues/64

Puede consultar la API de $state aquí: http://angular-ui.github.io/ui-router/site/#/api/ui.router.state . $ State

Tengo un SPA Angular que presenta una variedad de listas de recomendaciones, y un Mapa de Google de ubicaciones, basado en diferentes cortes de algunos datos de restaurantes (ver http://m.amsterdamfoodie.nl/ ). Quiero que cada una de estas listas tenga su propia URL. Para que Google pueda rastrear las diferentes listas, uso las etiquetas <a> para la navegación offcanvas.

Actualmente, la etiqueta <a> provoca una actualización de la vista, que es muy notable con el mapa.

  • Puedo evitar esto usando ng-click y $event.preventDefault() (vea los fragmentos de código a continuación), pero luego necesito implementar un medio para actualizar la URL del navegador.
  • Pero al probar el $state de Angular o el history.pushstate del navegador, el estado final, acabo de activar cambios de estado y la vista de actualización ...!

Por lo tanto, mi pregunta es ¿cómo puedo actualizar un modelo y la URL, pero sin actualizar la vista? (Consulte también Angular / UI-Router - ¿Cómo puedo actualizar la URL sin actualizar todo? )

He experimentado con muchos enfoques y actualmente tengo este html

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

En el controlador:

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

Y, lo que creo que está sucediendo es que estoy activando el código de $stateProvider :

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''

Una pista posible es que con el código siguiente si carga, por ejemplo, http://afmnew.herokuapp.com/criteria/cuisine/italian , la vista se actualiza a medida que navega, mientras que si carga http://afmnew.herokuapp.com/ no hay actualizaciones, pero no actualizaciones de URL en su lugar. No entiendo por qué eso está sucediendo en absoluto.


La respuesta corta terminó siendo no colocar el mapa dentro de una vista que cambia. La respuesta aceptada proporciona muchos más detalles sobre cómo estructurar una página con subvistas, pero el punto clave no es hacer que el mapa sea parte de la vista, sino conectar su comportamiento a una vista que sí cambie y usar un controlador para actualizar los iconos del mercado.


Sobre la base de nuestras discusiones anteriores, quiero darle una idea de cómo usar UI-Router aquí. Creo, entiendo su desafío correctamente ... Hay un ejemplo práctico . Si esto no es totalmente suites, por favor tómelo como un poco de inspiración

NEGACIÓN DE RESPONSABILIDAD: con un plunker, no pude lograr esto: http://m.amsterdamfoodie.nl/ , pero el principio debería ser similar en ese ejemplo

Entonces, hay una definición de estado (solo tenemos dos estados)

$stateProvider .state(''main'', { url: ''/'', views: { ''@'' : { templateUrl: ''tpl.layout.html'', controller: ''MainCtrl'', }, ''right@main'' : { templateUrl: ''tpl.right.html'',}, ''map@main'' : { templateUrl: ''tpl.map.html'', controller: ''MapCtrl'', }, ''list@main'' : { 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'', }, }, }) }];

Este sería nuestro principal 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>

Como podemos ver, el estado principal tiene como objetivo estas vistas anidadas del estado principal: ''viewName @ main '', por ejemplo, ''right@main''

También la subvista, main.criteria se inyecta en las vistas de diseño .

Su url comienza con un signo ^ ( url : ''^/criteria/:criteria/:value'' ), que permite tener / slash para la barra principal y no doble para el hijo

Y también hay controladores, están aquí un poco ingenuos, pero deberían mostrar que, en el fondo, podría haber una carga de datos real (según los criterios).

Lo más importante aquí es que el PADRE MainCtrl crea el $scope.Model = {} . Esta propiedad será (gracias a la herencia) compartida entre padres e hijos. Es por eso que todo esto funcionará:

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]; } })

Esto debería tener una idea de cómo podemos usar las funciones que nos proporciona el UI-Router:

Compruebe el extracto anterior aquí , en el ejemplo de trabajo

Extender: nuevo plunker here

Si no queremos que se vuelva a crear la vista del mapa, podemos omitir esa forma en la definición del estado secundario:

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

Ahora nuestro mapa VIEW solo recibirá los cambios en el modelo (se podría ver) pero la vista y el controlador no se volverán a mostrar

TAMBIÉN, hay otro plunker http://plnkr.co/edit/y0GzHv?p=preview que usa el controllerAs

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

y que podría ser usado así:

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

El último plunker está http://plnkr.co/edit/y0GzHv?p=preview


puede utilizar la herencia de ámbito para actualizar la URL sin actualizar la vista

$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'']; }] } })

Si la vista secundaria está dentro de la vista principal, ambos controladores comparten el mismo ámbito. de modo que puede colocar una vista ui ficticia (o necesaria) dentro de la vista primaria que se rellenará con la vista secundaria.

e inserte un

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

función en el controlador principal que será llamada por el controlador secundario en la carga del controlador. así que cuando un usuario hace clic

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

solo se actualizarán el controlador secundario y la vista secundaria. entonces puede llamar a la función de alcance padre con los parámetros necesarios.