Redirigir un estado al subestado predeterminado con UI-Router en AngularJS

89

Estoy creando una página basada en pestañas que muestra algunos datos. Estoy usando UI-Router en AngularJs para registrar estados.

Mi objetivo es tener una pestaña predeterminada abierta al cargar la página. Cada pestaña tiene subpestañas, y me gustaría tener una subpestaña predeterminada abierta al cambiar de pestaña.

Estaba probando con la onEnterfunción y en el interior estoy usando, $state.go('mainstate.substate');pero parece que no funciona debido a problemas de efecto de bucle (en state.go para subestimar, llama a su estado principal y así sucesivamente, y se convierte en un bucle).

$stateProvider

.state('main', {
  url: '/main',
  templateUrl: 'main.html',
  onEnter: function($state) {
    $state.go('main.street');
  }
})

.state('main.street', {
  url: '/street',
  templateUrl: 'submenu.html',
  params: {tabName: 'street'}
})

Aquí creé una demostración de plunker .

Por ahora todo funciona, excepto que no tengo abierta la pestaña predeterminada y eso es exactamente lo que necesito.

Gracias por sus sugerencias, opiniones e ideas.

León
fuente

Respuestas:

172

Actualización: 1.0 en adelante Admite redirectTo fuera de la caja.

https://ui-router.github.io/ng1/docs/latest/interfaces/state.statedeclaration.html#redirectto


Creé un ejemplo aquí .

Esta solución viene de un buen "Comentario" a un problema con la redirección usando .when() ( https://stackoverflow.com/a/27131114/1679310 ) y una solución realmente genial (por Chris T, pero la publicación original fue por yahyaKacem)

https://github.com/angular-ui/ui-router/issues/1584#issuecomment-75137373

Primero, extendamos main con la configuración de redirección:

$stateProvider
    .state('main', {
      url: '/main',
      templateUrl: 'main.html',
      redirectTo: 'main.street',
    })

Y agregue solo estas pocas líneas en ejecución

app.run(['$rootScope', '$state', function($rootScope, $state) {

    $rootScope.$on('$stateChangeStart', function(evt, to, params) {
      if (to.redirectTo) {
        evt.preventDefault();
        $state.go(to.redirectTo, params, {location: 'replace'})
      }
    });
}]);

De esta forma podemos ajustar cualquiera de nuestros estados con su redirección predeterminada ... Compruébalo aquí

EDITAR: opción agregada del comentario de @Alec para preservar el historial del navegador.

Radim Köhler
fuente
4
Esto parece golpear el botón de retroceso.
Scott Sword
6
@ Swordfish0321 para arreglar el botón de retroceso, haga este pequeño cambio: $state.go(to.redirectTo, params, {location: 'replace'});Esto hará que el nuevo estado reemplace el estado anterior (es decir, el que estamos siendo redirigidos) en el historial. Ver la documentación sobre $ state.go: angular-ui.github.io/ui-router/site/#/api/...
Alec
2
Solo quería agregar que esto estaba muy cerca de lo que quería hacer, pero quería la URL predeterminada en lugar de reemplazarla, esto se logró fácilmente cambiando '$stateChangeStart'a'$stateChangeSuccess'
Matti Price
6
ui-router 1.0 tiene soporte integrado para esto: ui-router.github.io/guide/ng1/…
Gert-Jan
21

De hecho, incluso si esta solución propuesta por Radim hizo exactamente el trabajo, necesitaba recordar la subpestaña (estado) de cada pestaña.

Así que encontré otra solución que hace lo mismo pero que también recuerda cada subestado de pestaña.

Todo lo que tenía que hacer era instalar ui-router-extras y usar la función de redireccionamiento de estado profundo :

$stateProvider
  .state('main.street', {
     url: '/main/street',
     templateUrl: 'main.html',
     deepStateRedirect: { default: { state: 'main.street.cloud' } },
  });

¡Gracias!

León
fuente
12

A partir de la versión 1.0 del ui-router, admite una redirectTopropiedad. Por ejemplo:

.state('A', {
  redirectTo: 'A.B'
})
BBlackwo
fuente
7

Desde la versión 1.0 de ui-router, se ha introducido un enlace predeterminado utilizando IHookRegistry.onBefore () como se muestra en el ejemplo de subestado predeterminado controlado por datos en http://angular-ui.github.io/ui-router/feature-1.0/ interfaces / transición.ihookregistry.html # onbefore

// state declaration
{
  name: 'home',
  template: '<div ui-view/>',
  defaultSubstate: 'home.dashboard'
}

var criteria = {
  to: function(state) {
    return state.defaultSubstate != null;
  }
}
$transitions.onBefore(criteria, function($transition$, $state) {
  return $state.target($transition$.to().defaultSubstate);
});
ThmX
fuente
Este tipo de trabajo para mí, aunque tuve que modificarlo (también usando ES6)$transitions.onBefore({ to: state => state.defaultSubstate != null }, trans => trans.router.stateService.target(trans.to().defaultSubstate));
yorch
3
app.config(function($stateProvider,$urlRouterProvider){

    $urlRouterProvider.when("/state","/state/sub-state");

    })
shubam yadav
fuente
1
¿Puede proporcionar una explicación de lo que hace esto y por qué es mejor que las respuestas ya existentes?
Equalsk
Esta solución es la más fácil y me funcionó bien.
BuffMcBigHuge
Esta es la mejor respuesta con diferencia. Más conciso que usar eventos de cambio. No es necesario agregar paquetes. No sé cómo eso no está claro para nadie. No sé cómo se votó tanto a favor de la respuesta aceptada.
CodeWarrior
1

Si alguien viene aquí para obtener una respuesta sobre cómo implementar una redirección simple para un estado y, como me sucedió a mí, no tiene la oportunidad de usar el nuevo enrutador ...

Obviamente, nuevamente, si puede, la respuesta de @bblackwo es excelente:

$stateProvider.state('A', {
  redirectTo: 'B',
});

Si no puede, simplemente redirija manualmente:

$stateProvider.state('A', {
  controller: $state => {
    $state.go('B');
  },
});

¡Espero que ayude!

José Daniel Vivar Personat
fuente