web-dev-qa-db-fra.com

Backbone.js: obtenir l'itinéraire actuel

À l’aide de Backbone, m’obtient-il le nom de l’itinéraire actuel? Je sais comment me lier aux événements de changement d'itinéraire, mais j'aimerais pouvoir déterminer l'itinéraire actuel à d'autres moments, entre les changements.

134
Drew Dara-Abrams

Si vous avez instancié un routeur dans votre application, la ligne suivante renvoie le fragment actuel:

Backbone.history.getFragment();

De la documentation Backbone.js :

"[...] History sert de routeur global (par image) pour gérer les événements de hashchange ou pushState, faire correspondre la route appropriée et déclencher des rappels. Vous ne devriez jamais avoir à en créer un vous-même - vous devriez utiliser la référence à Backbone.history qui sera créée automatiquement pour vous si vous utilisez des routeurs avec des routes. [.. .] "

Si vous avez besoin du nom de la fonction liée à ce fragment, vous pouvez créer quelque chose comme ceci dans la portée de votre routeur:

alert( this.routes[Backbone.history.getFragment()] );

Ou comme ceci de l'extérieur de votre routeur:

alert( myRouter.routes[Backbone.history.getFragment()] );
208
Robert

La réponse de Robert est intéressant, mais malheureusement, cela ne fonctionnera que si le hachage est exactement tel que défini dans l'itinéraire. Si, par exemple, vous avez un itinéraire pour user(/:uid), il ne sera pas mis en correspondance si le Backbone.history.fragment Est soit "user" Ou "user/1" (Les deux étant les deux cas d'utilisation les plus évidents pour une telle route). En d'autres termes, le nom de rappel approprié ne sera trouvé que si le hachage est exactement "user(/:uid)" (hautement improbable).

Depuis que j’avais besoin de cette fonctionnalité, j’ai étendu le Backbone.Router Avec une fonction current- qui réutilise une partie du code utilisé par les objets History et Router pour faire correspondre le fragment en cours aux routes définies afin de déclencher le rappel approprié. . Pour mon cas d'utilisation, il prend le paramètre facultatif route, qui, s'il est défini sur une valeur véridique, renverra le nom de fonction correspondant défini pour la route. Sinon, le fragment de hachage actuel sera renvoyé à partir de Backbone.History.fragment.

Vous pouvez ajouter le code à votre extension existante où vous initialisez et configurez le routeur Backbone.

var Router = new Backbone.Router.extend({

    // Pretty basic stuff
    routes : {
        "home" : "home",
        "user(:/uid)" : "user",
        "test" : "completelyDifferent"
    },

    home : function() {
        // Home route
    },

    user : function(uid) {
        // User route
    },

    // Gets the current route callback function name
    // or current hash fragment
    current : function(route){
        if(route && Backbone.History.started) {
            var Router = this,
                // Get current fragment from Backbone.History
                fragment = Backbone.history.fragment,
                // Get current object of routes and convert to array-pairs
                routes = _.pairs(Router.routes);

            // Loop through array pairs and return
            // array on first truthful match.
            var matched = _.find(routes, function(handler) {
                var route = handler[0];

                // Convert the route to RegExp using the 
                // Backbone Router's internal convert
                // function (if it already isn't a RegExp)
                route = _.isRegExp(route) ? route :  Router._routeToRegExp(route);

                // Test the regexp against the current fragment
                return route.test(fragment);
            });

            // Returns callback name or false if 
            // no matches are found
            return matched ? matched[1] : false;
        } else {
            // Just return current hash fragment in History
            return Backbone.history.fragment
        }
    }
});

// Example uses:
// Location: /home
// console.log(Router.current()) // Outputs 'home'
// Location: /user/1
// console.log(Router.current(true)) // Outputs 'user'
// Location: /user/2
// console.log(Router.current()) // Outputs 'user/2'
// Location: /test
// console.log(Router.current(true)) // Outputs 'completelyDifferent'

Je suis sûr que certaines améliorations pourraient être apportées, mais c'est un bon moyen de commencer. De plus, il est facile de créer cette fonctionnalité sans étendre l'objet Route. Je l'ai fait parce que c'était le moyen le plus pratique pour mon installation.

Je n'ai pas encore testé cela complètement, donc faites-le-moi savoir si quelque chose se passe au sud.


MISE À JOUR 25/04/2013

J'ai apporté quelques modifications à la fonction. Ainsi, au lieu de renvoyer le nom de rappel de hachage ou de route, je retourne un objet avec fragment, params et route afin que vous puissiez accéder à toutes les données de la route en cours, comme vous le feriez de la route. un événement.

Vous pouvez voir les modifications ci-dessous:

current : function() {
    var Router = this,
        fragment = Backbone.history.fragment,
        routes = _.pairs(Router.routes),
        route = null, params = null, matched;

    matched = _.find(routes, function(handler) {
        route = _.isRegExp(handler[0]) ? handler[0] : Router._routeToRegExp(handler[0]);
        return route.test(fragment);
    });

    if(matched) {
        // NEW: Extracts the params using the internal
        // function _extractParameters 
        params = Router._extractParameters(route, fragment);
        route = matched[1];
    }

    return {
        route : route,
        fragment : fragment,
        params : params
    };
}

Voir le code précédent pour plus de commentaires et d'explications, ils se ressemblent généralement.

56
Simon Kjellberg

Pour obtenir la route d’appel (ou l’URL) auprès du gestionnaire de route appelé, vous pouvez l’obtenir en cochant

 Backbone.history.location.href ... l'URL complète 
 Backbone.history.location.search ... chaîne de requête à partir de? 

Je suis arrivé à la recherche de cette réponse, alors je suppose que je devrais laisser ce que j'ai trouvé.

9
yoshi

Si vous utilisez le paramètre racine du routeur, vous pouvez également l'inclure pour obtenir le fragment "réel".

(Backbone.history.options.root || "") + "/" + Backbone.history.fragment
6
user1310662

Voici une version un peu plus verbeuse (ou, selon vos goûts, plus lisible) de réponse de Simon :

current: function () {
  var fragment = Backbone.history.fragment,
      routes = _.pairs(this.routes),
      route,
      name,
      found;

  found = _.find(routes, function (namedRoute) {
    route = namedRoute[0];
    name = namedRoute[1];

    if (!_.isRegExp(route)) {
      route = this._routeToRegExp(route);
    }

    return route.test(fragment);
  }, this);

  if (found) {
    return {
      name: name,
      params: this._extractParameters(route, fragment),
      fragment: fragment
    };
  }
}
5
Dan Abramov

Si vous regardez la source de Router, vous verrez que lorsque le routeur déclenche l'événement en disant que quelque chose change, il le nomme comme "route: nom".

http://documentcloud.github.com/backbone/docs/backbone.html#section-84

Vous pouvez toujours connecter l'événement "route" sur le routeur et le stocker pour obtenir la route actuelle.

4
Brian Genisio