Backbone: router.navigate n'appelle pas le routeur à moins que le hachage ne soit modifié

Créé le 2 oct. 2011  ·  22Commentaires  ·  Source: jashkenas/backbone

J'essaie d'utiliser des URL sans hashbangs, ce qui cause des problèmes.

En testant, j'ai fait ça.

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

L'URL est mise à jour mais mon routeur n'est pas appelé. Au début, je pensais que l'itinéraire ne correspondait pas, mais si j'actualise la page, l'itinéraire correspond avec succès.

Ensuite, j'ai essayé ceci :

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

Et tout fonctionne très bien, il semble que le routeur ne soit appelé que si un changement de hachage est déclenché.

Commentaire le plus utile

C'est en effet un comportement intéressant de router.navigate() que j'ai déjà rencontré en essayant de forcer un itinéraire à se recharger. Voici ce que j'ai fini par faire :

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

Ce n'est pas _explicitement_ documenté dans le cadre de l'API, mais cela fait certainement le travail. Cela me semble raisonnable que router.navigate( 'current/path', true ) déclenche à nouveau l'appel du gestionnaire de route.

Quelqu'un d'autre veut-il intervenir ?

Tous les 22 commentaires

Fonctionne si je supprime l'inital /
Je suppose que cela doit correspondre exactement à vos itinéraires

C'est en effet un comportement intéressant de router.navigate() que j'ai déjà rencontré en essayant de forcer un itinéraire à se recharger. Voici ce que j'ai fini par faire :

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

Ce n'est pas _explicitement_ documenté dans le cadre de l'API, mais cela fait certainement le travail. Cela me semble raisonnable que router.navigate( 'current/path', true ) déclenche à nouveau l'appel du gestionnaire de route.

Quelqu'un d'autre veut-il intervenir ?

Je suis également tombé sur ce problème. Voici mon cas d'utilisation spécifique :

J'utilise des requêtes multimédias pour fournir une interface réactive pour toutes les tailles d'écran. Mes vues contiennent des éléments qui ne répondent pas aux requêtes multimédias, j'ai donc écrit une fonction pour écouter les événements de redimensionnement et refaire le rendu de la page si j'en ai besoin. Plutôt que de référencer et de rendre des vues individuelles, j'ai pensé appeler simplement

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

Je préfère ne pas avoir à faire référence du tout à Backbone.history. Il serait préférable que le routeur dispose d'une méthode de rafraîchissement ou de rechargement :

router.refresh(true);

J'ai eu le même problème. @Ansman peux-tu montrer quels sont tes itinéraires ? Mon problème était que la barre oblique principale est automatiquement supprimée par l'historique lors de l'obtention du hachage, car il s'agit de la racine par défaut.

Oui -- vous ne devriez jamais avoir de barre oblique au début ... que ce soit dans vos itinéraires ou dans vos appels à naviga(). Cela dit, il y a un commit sur le maître qui supprime avec force toutes les barres obliques de début, donc cela ne devrait plus conduire à un comportement bogué.

Enfin, oui, votre routeur ne devrait se déclencher que si l'itinéraire a réellement été modifié.

Je voudrais signaler qu'un appel explicite à router.navigate ("route", true) devrait déclencher la route même si la route n'a pas été modifiée dans le hachage

@danroberts Il ne semble pas possible pour le moment de forcer le déclenchement de la route si le hachage n'a pas changé. J'ai essayé router.navigate("route/", {trigger:true}); et ça ne marche pas. Un hack rapide consiste simplement à appeler router.route_name() .

@olalonde J'ai utilisé la méthode de @wookiehangover ci-dessus avec de bons résultats. Je viens d'écrire une fonction personnalisée qui vérifie si la route vers laquelle j'essaie d'aller est la même que le hachage actuel, puis appelle soit router.navigate soit history.loadURL.

Il semble raisonnable que cela puisse faire partie du tableau d'options, quelque chose comme refresh:true si vous voulez qu'il déclenche la route malgré tout. Aussi, peut-être qu'une mise à jour de la documentation semble s'imposer, puisque {trigger: true} va logiquement déclencher la route...

Voici le problème que j'ai avec cette fermeture de ce bogue :

Un point clé de l'utilisation du backbone est de gérer l'analyse des routes, puis d'appeler une fonction basée sur la route. N'ayant pas la capacité de déterminer les cas où un « rechargement » est ok via le backbone directement, nous devons faire quelque chose à cet effet :

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

Est-ce que ça marche? oui, mais il semble que ce soit un cas d'utilisation totalement valide qui serait bien d'avoir dans la plate-forme.

Pour info, j'ai vu #1214 avant ce fil et posté le même commentaire.

Backbone Router n'autorise pas ce type d'action car il écoute un événement de changement d'URL pour déclencher des actions routées.

Vous devez intercepter le contrôle qui déclenche l'action et réinitialiser l'action du routeur.

J'ai créé un exemple jsFiddle ici :
http://goo.gl/wPulo

et un article de blog ici :
http://goo.gl/mJM2i

J'ai rencontré ce problème aujourd'hui et je voudrais juste ajouter mes 2 cents :

Cela semble être un comportement peu intuitif qui, lors de la définition explicite de trigger: true , ne déclenchera pas l'événement à moins que le hachage n'ait changé.

Mon vote est en faveur de trigger: true déclenchant l'itinéraire quelle que soit la condition.

Un exemple concret est lorsque vous souhaitez actualiser la page actuelle sur laquelle vous vous trouvez, ce qui serait impossible à faire avec le comportement actuel de trigger: true .

+1 pour la méthode KenPerkins ou quelque chose de similaire à intégrer dans les routeurs BB.

+1 pour le processus naviguer sur la même page si { trigger: true } est passé

J'ai passé 3 heures à essayer de trouver pourquoi la méthode roter.navigate() ne fonctionnait pas sur mon application. Je pense que les documents BB devraient inclure une notification sur ce problème.

Ma solution laide mais rapide consistait à appeler une méthode router.navigate() avant la méthode réelle.

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

Pour l'instant, ça a marché. Mais s'il y avait une option refresh:true , je l'utiliserais certainement...

Je laisse juste mes réflexions à ce sujet car c'est un problème que je viens de rencontrer aujourd'hui. Il semble très peu intuitif que la route ne soit pas appelée lorsque vous transmettez explicitement le hachage des options {trigger: true} à router.navigate. J'aimerais voir l'ajout d'une option refresh:true telle que @onuradsay l' a suggéré.

+1 pour la praticité de l' idée de @onuradsay

+1. Nous devrions toujours être en mesure de recevoir l'événement, puis de déterminer dans notre application si une actualisation est nécessaire. Nous pouvons comprendre cela avec de nombreux hacks mentionnés ci-dessus, mais ce n'est pas très propre. Je pense que ce comportement est suffisamment courant pour le mettre dans le routeur.

J'ai peur que ça n'arrive pas. Le fait que les gens le demandent est en fait plus une incitation à _supprimer_ trigger:true qu'à déclencher inconditionnellement l'événement. Laissez-moi expliquer:

Les événements dans Backbone consistent à être notifiés lorsque l'état est modifié. Tout comme dans les modèles, faire :

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

... ne déclenchera pas d'événement la deuxième fois, car aucun état n'a été modifié ... essayer de naviguer jusqu'à l'emplacement où vous vous trouvez déjà n'est _pas_ un changement d'état et ne déclenchera pas d'événement.

Si vous souhaitez qu'un rappel soit déclenché chaque fois qu'un bouton est cliqué, ajoutez simplement le rappel. Ou si vous souhaitez utiliser les événements de Backbone pour le faire - appelez simplement object.trigger("myEvent")

On dirait qu'au lieu de trigger:true il devrait supposer vrai et avoir l'option silent:false .

Si nous n'ajoutons pas cette fonctionnalité, nous devrons toujours faire quelque chose comme ça dans nos gestionnaires de boutons -

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

Merci @dankantor pour la super astuce !

Si vous devez faire ce cas d'utilisation (pour forcer le rechargement de la même page/hachage), ne voudriez-vous pas Backbone.history.getFragment() au lieu de history.fragment afin de ne pas accéder aux propriétés de l'historique ? Semble plus propre.

J'ai créé une méthode Backbone.history.refresh pour forcer le rechargement. Ensuite, dans certains projets, je remplace le comportement de navigation par défaut pour recharger, peu importe si le hachage a changé :

      _.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);
        };
Cette page vous a été utile?
0 / 5 - 0 notes