Backbone: router.navigate ruft den Router nicht auf, es sei denn, der Hash wird geändert

Erstellt am 2. Okt. 2011  ·  22Kommentare  ·  Quelle: jashkenas/backbone

Ich versuche, URLs ohne Hashbangs zu verwenden, was etwas Kummer verursacht.

Beim Testen habe ich das gemacht.

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

Die URL wird aktualisiert, aber mein Router wird nicht aufgerufen. Zuerst dachte ich, dass die Route nicht übereinstimmt, aber wenn ich die Seite aktualisiere, wird die Route erfolgreich abgeglichen.

Dann habe ich das probiert:

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

Und alles funktioniert einwandfrei, anscheinend wird der Router nur aufgerufen, wenn ein Hashchange ausgelöst wird.

Hilfreichster Kommentar

Dies ist in der Tat ein interessantes Verhalten von router.navigate() , auf das ich schon einmal gestoßen bin, als ich versucht habe, das Neuladen einer Route zu erzwingen. Folgendes habe ich letztendlich getan:

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

Das ist nicht _ausdrücklich_ als Teil der API dokumentiert, aber es erledigt die Aufgabe auf jeden Fall. Scheint mir vernünftig, dass router.navigate( 'current/path', true ) erneuten Aufruf des Route-Handlers auslösen soll.

Möchte sich noch jemand dazu einmischen?

Alle 22 Kommentare

Funktioniert, wenn ich die Initiale entferne /
Denke, es muss genau zu deinen Routen passen

Dies ist in der Tat ein interessantes Verhalten von router.navigate() , auf das ich schon einmal gestoßen bin, als ich versucht habe, das Neuladen einer Route zu erzwingen. Folgendes habe ich letztendlich getan:

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

Das ist nicht _ausdrücklich_ als Teil der API dokumentiert, aber es erledigt die Aufgabe auf jeden Fall. Scheint mir vernünftig, dass router.navigate( 'current/path', true ) erneuten Aufruf des Route-Handlers auslösen soll.

Möchte sich noch jemand dazu einmischen?

Ich bin auch auf dieses Problem gestoßen. Hier ist mein konkreter Anwendungsfall:

Ich verwende Medienabfragen, um eine reaktionsschnelle Benutzeroberfläche für alle Bildschirmgrößen bereitzustellen. Meine Ansichten enthalten einige Elemente, die nicht auf Medienanfragen reagieren, also habe ich eine Funktion geschrieben, um auf Ereignisse zur Größenänderung zu hören und die Seite bei Bedarf neu zu rendern. Anstatt einzelne Ansichten zu referenzieren und zu rendern, dachte ich, ich würde einfach anrufen

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

Ich möchte lieber gar nicht auf Backbone.history verweisen. Es wäre am besten, wenn der Router eine Refresh- oder Reload-Methode hätte:

router.refresh(true);

Ich hatte das gleiche Problem. @Ansman kannst du zeigen, was deine Routen sind? Mein Problem war, dass der führende Schrägstrich beim Abrufen des Hashs automatisch vom Verlauf entfernt wird, da es sich um das Standard-Root handelt.

Ja -- Sie sollten niemals einen führenden Schrägstrich haben ... weder in Ihren Routen noch in Ihren navigation()-Aufrufen. Das heißt, es gibt einen Commit auf master, der alle führenden Schrägstriche energisch entfernt, so dass dies nicht mehr zu fehlerhaftem Verhalten führen sollte.

Schließlich sollte Ihr Router nur dann feuern, wenn die Route tatsächlich geändert wurde.

Ich möchte einläuten, dass ein expliziter Aufruf von router.navigate("route", true) die Route auslösen soll, auch wenn die Route im Hash nicht geändert wurde

@danroberts Es scheint im Moment nicht möglich zu sein, das Auslösen der Route zu erzwingen, wenn sich der Hash nicht geändert hat. Ich habe es versucht router.navigate("route/", {trigger:true}); und es funktioniert nicht. Ein schneller Hack ist, einfach router.route_name() aufzurufen.

@olalonde Ich habe die obige Methode von

Es scheint vernünftig, dass dies Teil des Options-Arrays sein könnte, etwa refresh:true, wenn die Route trotzdem ausgelöst werden soll. Vielleicht scheint auch eine Aktualisierung der Dokumentation angebracht, da {trigger: true} logischerweise die Route auslösen wird ...

Hier ist das Problem, das ich mit diesem Schließen dieses Fehlers habe:

Ein wichtiger Punkt bei der Verwendung von Backbone ist das Parsen von Routen und das anschließende Aufrufen einer Funktion basierend auf der Route. Da wir nicht in der Lage sind, Fälle zu bestimmen, in denen ein "Nachladen" direkt über das Backbone in Ordnung ist, müssen wir Folgendes tun:

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

Funktioniert das? ja, aber es fühlt sich so an, als wäre dies ein absolut gültiger Anwendungsfall, der in der Plattform schön wäre.

Zu Ihrer Information Ich habe #1214 vor diesem Thread gesehen und denselben Kommentar gepostet.

Der Backbone-Router lässt diese Art von Aktion nicht zu, da er auf ein URL-Änderungsereignis lauscht, um weitergeleitete Aktionen auszulösen.

Sie müssen die Steuerung abfangen, die die Aktion auslöst und die Aktion des Routers zurücksetzen.

Ich habe hier ein jsFiddle-Beispiel erstellt:
http://goo.gl/wPulo

und ein Blogbeitrag hier:
http://goo.gl/mJM2i

Bin heute auf diese Ausgabe gestoßen und möchte nur meine 2 Cent hinzufügen:

Scheint ein nicht intuitives Verhalten zu sein, das beim expliziten Festlegen von trigger: true das Ereignis nicht auslöst, es sei denn, der Hash hat sich geändert.

Meine Stimme ist dafür, dass trigger: true die Route unabhängig von der Bedingung auslöst.

Ein Beispiel aus der Praxis ist, wenn Sie die aktuelle Seite aktualisieren möchten, auf der Sie sich befinden, was mit dem aktuellen Verhalten von trigger: true unmöglich wäre.

+1 für KenPerkins-Methode oder ähnliches zur Integration in BB-Router.

+1 für die Prozessnavigation auf derselben Seite, wenn { trigger: true } übergeben wird

Ich habe 3 Stunden damit verbracht, herauszufinden, warum die Methode roter.navigate() in meiner Anwendung nicht funktioniert hat. Ich denke, BB-Dokumente sollten eine Benachrichtigung zu diesem Problem enthalten.

Meine hässliche, aber schnelle Lösung bestand darin, eine router.navigate() Methode vor der eigentlichen Methode aufzurufen.

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

Im Moment hat es funktioniert. Aber wenn es eine Option für refresh:true gäbe, würde ich sie definitiv verwenden...

Ich hinterlasse nur meine Gedanken dazu, da es sich um ein Problem handelt, auf das ich erst heute gestoßen bin. Es scheint sehr wenig intuitiv, dass die Route nicht aufgerufen wird, wenn Sie den {trigger: true} Optionshash explizit an router.navigate übergeben. Ich würde gerne eine Option refresh:true hinzufügen, wie sie

+1 für die Praktikabilität von @patrickod und @onuradsays Idee

+1. Wir sollten das Ereignis weiterhin empfangen und dann in unserer App feststellen können, ob eine Aktualisierung erforderlich ist. Wir können dies mit vielen der oben genannten Hacks herausfinden, aber es ist nicht sehr sauber. Ich denke, dieses Verhalten ist häufig genug, um es in den Router zu integrieren.

Ich fürchte, es wird nicht passieren. Die Tatsache, dass die Leute danach fragen, ist eigentlich mehr Ansporn, trigger:true zu _entfernen_, als das Ereignis bedingungslos auszulösen. Lassen Sie mich erklären:

Bei Ereignissen in Backbone geht es darum, benachrichtigt zu werden, wenn sich der Status ändert. Genau wie in Modellen:

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

... löst beim zweiten Mal kein Ereignis aus, da kein Zustand geändert wurde ... der Versuch, zu der Position zu navigieren, an der Sie sich bereits befinden, ist _keine_ Änderung des Zustands und löst kein Ereignis aus.

Wenn Sie möchten, dass ein Rückruf ausgelöst wird, wenn auf eine Schaltfläche geklickt wird, fügen Sie einfach den Rückruf hinzu. Oder wenn Sie Backbone-Ereignisse verwenden möchten, um dies zu tun - rufen Sie einfach object.trigger("myEvent") auf.

Anscheinend sollte es anstelle von trigger:true wahr annehmen und die Option silent:false .

Wenn wir diese Funktionalität jedoch nicht hinzufügen, müssen wir in unseren Button-Handlern immer so etwas tun -

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

Danke @dankantor für den tollen Trick!

Wenn Sie diesen Anwendungsfall ausführen müssen (um das erneute Laden derselben Seite / desselben Hashs zu erzwingen), möchten Sie nicht Backbone.history.getFragment() anstelle von history.fragment verwenden, damit Sie nicht auf die Eigenschaften des Verlaufs zugreifen? Scheint sauberer zu sein.

Ich habe eine Backbone.history.refresh-Methode erstellt, um das Neuladen zu erzwingen. Dann überschreibe ich in einigen Projekten das Standardnavigationsverhalten, um neu zu laden, unabhängig davon, ob sich der Hash geändert hat:

      _.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);
        };
War diese Seite hilfreich?
0 / 5 - 0 Bewertungen