Backbone: router.navigate no llama al router a menos que se cambie el hash

Creado en 2 oct. 2011  ·  22Comentarios  ·  Fuente: jashkenas/backbone

Estoy tratando de usar URL sin hashbangs, lo que me está causando dolor.

Mientras probaba, hice esto.

<a href="#" onclick="router.navigate('/albums/<%= album.id %>', true); return false;">Show</a>

La URL está actualizada pero no se llama a mi enrutador. Al principio pensé que la ruta no coincidía, pero si actualizo la página, la ruta coincide correctamente.

Entonces probé esto:

<a href="#" onclick="router.navigate('/albums/<%= album.id %>', true);">Show</a>

Y todo funciona bien, parece que el enrutador solo se llama si se activa un cambio de hash.

Comentario más útil

De hecho, este es un comportamiento interesante de router.navigate() que me he encontrado antes al intentar forzar la recarga de una ruta. Esto es lo que terminé haciendo:

Backbone.history.loadUrl( Backbone.history.fragment )

Eso no está _explícitamente_ documentado como parte de la API, pero ciertamente hace el trabajo. Me parece razonable que router.navigate( 'current/path', true ) debería activar el controlador de ruta para que se vuelva a llamar.

¿Alguien más quiere intervenir en esto?

Todos 22 comentarios

Funciona si quito el inicial /
Supongo que debe coincidir exactamente con tus rutas.

De hecho, este es un comportamiento interesante de router.navigate() que me he encontrado antes al intentar forzar la recarga de una ruta. Esto es lo que terminé haciendo:

Backbone.history.loadUrl( Backbone.history.fragment )

Eso no está _explícitamente_ documentado como parte de la API, pero ciertamente hace el trabajo. Me parece razonable que router.navigate( 'current/path', true ) debería activar el controlador de ruta para que se vuelva a llamar.

¿Alguien más quiere intervenir en esto?

También me encontré con este problema. Aquí está mi caso de uso específico:

Estoy usando consultas de medios para proporcionar una interfaz receptiva para todos los tamaños de pantalla. Mis vistas tienen algunos elementos que no responden a las consultas de los medios, así que escribí una función para escuchar los eventos de cambio de tamaño y volver a renderizar la página si es necesario. En lugar de hacer referencia y representar vistas individuales, pensé que simplemente llamaría

router.navigate(Backbone.history.fragment, true)

Preferiría no tener que hacer referencia a Backbone.history en absoluto. Sería mejor si el enrutador tuviera un método de actualización o recarga:

router.refresh(true);

Tuve el mismo problema. @Ansman ¿puedes mostrar cuáles son tus rutas? Mi problema fue que el historial elimina automáticamente la barra inclinada al obtener el hash, ya que es la raíz predeterminada.

Sí, nunca debe tener una barra inclinada ... ni en sus rutas ni en sus llamadas de navegación (). Dicho esto, hay un compromiso en el maestro que elimina a la fuerza todas las barras inclinadas, por lo que esto ya no debería conducir a un comportamiento defectuoso.

Finalmente, sí, su enrutador solo debería activarse si la ruta realmente se ha cambiado.

Me gustaría decirle que una llamada explícita a router.navigate ("ruta", verdadero) debería activar la ruta incluso si la ruta no se ha cambiado en el hash

@danroberts No parece posible en este momento forzar el disparo de la ruta si el hash no ha cambiado. Probé router.navigate ("route /", {trigger: true}); y no funciona. Un truco rápido es simplemente llamar a router.route_name() .

@olalonde He estado usando el método de @wookiehangover anterior con buenos resultados. Acabo de escribir una función personalizada que verifica si la ruta a la que intento ir es la misma que el hash actual, y luego llama a router.navigate o history.loadURL.

Parece razonable que esto pueda ser parte de la matriz de opciones, algo así como refresh: true si desea que active la ruta independientemente. Además, tal vez una actualización de la documentación parece estar en orden, ya que {trigger: true} lógicamente va a activar la ruta ...

Aquí está el problema que tengo al cerrar este error:

Un punto clave del uso de la red troncal es manejar el análisis de rutas y luego llamar a una función basada en la ruta. Al carecer de la capacidad de determinar los casos en los que una "recarga" está bien a través de la red troncal directamente, tenemos que hacer algo al respecto:

        if (url == window.location.pathname + window.location.search) {
            Backbone.history.loadUrl(url);
            return false;
        }
        else if (app.router.isHandled(url)) {
            Backbone.history.navigate(url, {
                trigger: true
            });
            return false;
        }

¿Esto funciona? sí, pero parece que este es un caso de uso totalmente válido que sería bueno tener en la plataforma.

Para su información, vi el número 1214 antes de este hilo y publiqué el mismo comentario.

Backbone Router no permite este tipo de acción porque escucha un evento de cambio de URL para desencadenar cualquier acción enrutada.

Debe interceptar el control que desencadenó la acción y restablecer la acción del enrutador.

Creé un ejemplo de jsFiddle aquí:
http://goo.gl/wPulo

y una publicación de blog aquí:
http://goo.gl/mJM2i

Me encontré con este problema hoy y me gustaría agregar mis 2 centavos:

Parece un comportamiento poco intuitivo que cuando se establece explícitamente trigger: true no activará el evento a menos que el hash haya cambiado.

Mi voto está a favor de que trigger: true active la ruta sin importar la condición.

Un ejemplo del mundo real es cuando desea actualizar la página actual en la que se encuentra, eso sería imposible de hacer con el comportamiento actual de trigger: true .

+1 para el método KenPerkins o algo similar para integrarse en los enrutadores BB.

+1 para navegar por el proceso en la misma página si se pasa {trigger: true}

Pasé 3 horas tratando de averiguar por qué el método roter.navigate() no funcionó en mi aplicación. Creo que los documentos de BB deberían incluir una notificación sobre este problema.

Mi solución fea pero rápida fue llamar a un método router.navigate() antes del método real.

router.navigate();
router.navigate("app", true);

Por ahora, funcionó. Pero si hubiera una opción refresh:true , definitivamente la usaría ...

Solo dejo mis pensamientos sobre esto, ya que es un problema que acabo de encontrar hoy. Parece muy poco intuitivo que no se llame a la ruta cuando se pasa explícitamente el hash de opciones {trigger: true} a router.navigate. Me encantaría ver la adición de una opción refresh:true como la que sugirió @onuradsay .

+1 por la practicidad de la idea de @onuradsay

+1. Aún deberíamos poder recibir el evento y luego determinar en nuestra aplicación si se requiere una actualización. Podemos resolver esto con muchos de los trucos mencionados anteriormente, pero no es muy limpio. Creo que este comportamiento es lo suficientemente común como para ponerlo en el enrutador.

Me temo que no va a pasar. El hecho de que la gente lo pida es en realidad más ímpetu para _remove_ trigger:true que para despedir incondicionalmente el evento. Dejame explicar:

Los eventos en Backbone tienen que ver con ser notificados cuando se cambia de estado. Al igual que en modelos, haciendo:

model.set({title: "Boom"})
model.set({title: "Boom"})

... no activará un evento la segunda vez, ya que no se ha cambiado ningún estado ... intentar navegar a la ubicación en la que ya se encuentra _no_ es un cambio de estado y no activará un evento.

Si desea tener una devolución de llamada cada vez que se hace clic en un botón, simplemente agregue la devolución de llamada. O si desea usar los eventos de Backbone para hacerlo, simplemente llame a object.trigger ("myEvent")

Parece que en lugar de trigger:true debería asumir verdadero y tener la opción silent:false .

Sin embargo, si no agregamos esta funcionalidad, siempre tendremos que hacer algo como esto en nuestros controladores de botones:

if (Backbone.history.fragment === 'foo') {
    Backbone.history.loadUrl(Backbone.history.fragment);
 } else {
     router.navigate('foo', {'trigger': true});
}

¡Gracias @dankantor por el gran truco!

Si tiene que hacer este caso de uso (para forzar la recarga de la misma página / hash), ¿no querría Backbone.history.getFragment () en lugar de history.fragment para no acceder a las propiedades del historial? Parece más limpio.

Creé un método Backbone.history.refresh para forzar la recarga. Luego, en algunos proyectos, anulo el comportamiento de navegación predeterminado para recargar independientemente de si el hash ha cambiado:

      _.extend(Backbone.History.prototype, {
            refresh: function() {
                this.loadUrl(this.fragment);
            }
        });

        var routeStripper = /^[#\/]/;
        var origNavigate = Backbone.History.prototype.navigate;
        Backbone.History.prototype.navigate = function (fragment, options) {
            var frag = (fragment || '').replace(routeStripper, '');
            if (this.fragment == frag)
                this.refresh();
            else
                origNavigate.call(this, fragment, options);
        };
¿Fue útil esta página
0 / 5 - 0 calificaciones