2011-10-13 12 views
35

Sto separando le viste e il router in file separati con require. Quindi ho un file main.js che crea un'istanza del router e inoltre visualizza la mia vista predefinita.Utilizzo del router Backbone.js per navigare tra le viste modularizzate con require.js

Il mio router ha una vista ('Visualizza /: id') e modifica ('Modifica /: id') come rotte. In main.js, quando istanzio il router, posso hardcode router.navigate ('View/1', true) e la navigazione funziona bene. Nel mio file di visualizzazione, quando clicco sul link di modifica, voglio chiamare router.navigate ('Visualizza /' + id, vero), ma non sono sicuro di come dovrei farlo.

Ho avuto successo chiamando Backbone.history.navigate ('Visualizza /' + id, vero), ma non mi sento come dovrei fare affidamento sull'oggetto Backbone globale.

Ho provato a passare ({router: appRouter}) alle mie visualizzazioni, quindi ho potuto usare this.options.router.navigate(), tuttavia non funzionava per me.

Nel caso foste curiosi, ecco un mucchio di codice dalla mia app:

Router:

define(['./View', './Edit'], function (View, Edit) { 
    return Backbone.Router.extend({ 
     routes: { 
      'View/:id': 'view', 
      'Edit/:id': 'edit' 
     }, 

     view: function (id) { 
      var model = this.collection.get(id); 
      var view = new View({ model: model }); 
      view.render(); 
     }, 

     edit: function (id) { 
      var model = this.collection.get(id); 
      var edit = new Edit({ model: model }); 
      edit.render(); 
     } 
    }); 
}); 

Vista:

define(function() { 
    return Backbone.View.extend({ 
     template: Handlebars.compile($('#template').html()), 

     events: { 
      'click .edit': 'edit' 
     }, 

     render: function() { 
      //Create and insert the cover letter view 
      $(this.el).html(this.template(this.model.toJSON())); 
      $('#View').html(this.el); 

      return this; 
     }, 

     edit: function() { 
      Backbone.history.navigate('Edit/' + this.model.id, true); 
     }, 
    }); 
}); 
+0

Ciao uomo, sto facendo qualcosa come il tuo, con l'intenzione di usare router.navigate() nel mio modulo View. E come hai ottenuto questo alla fine? Grazie molto in anticipo. – chaonextdoor

+4

Ho finito per utilizzare Backgone.history.navigate. Dal momento che sto separando le mie viste in singoli file per visualizzazioni, router e modelli e utilizzando require.js per caricarli. Era troppo difficile passare un router o un oggetto evento a tutte le mie viste. Il globale sembrava avere più senso, dal momento che Backbone era già nello spazio dei nomi globale. – MrGrigg

+1

quindi backbone.history.navigate è uguale a router.navigate? – chaonextdoor

risposta

20

Come con praticamente tutta la domanda Backbone, ci sono un sacco di modi per gestire questo. Il modo in cui mi sono avvicinato nel mio progetto attuale è stato quello di mettere tutto in uno spazio dei nomi personalizzato globale, e l'uso che per passare intorno i riferimenti necessari:

var MyNamespace = {}; 

MyNamespace.init = function() { 
    MyNamespace.appView = new MyAppView(); 
    MyNamespace.router = new MyRouter(); 
    // etc 
} 

Visualizzazioni potrebbe quindi fare riferimento a MyNamespace.router se necessario. Ma sembra che questo non funziona/non è incoraggiata con require.js, ecco sono alcune altre opzioni:

  • Non bisogna mai chiamare il router in modo esplicito -, invece, cambiare un oggetto di stato globale che il router ascolta. Questo è in realtà come ho fatto le cose nel mio attuale progetto - vedi this response per maggiori dettagli.

  • Collegare il router alla vista di livello superiore, spesso chiamato AppView, renderlo accessibile a livello globale e utilizzare AppView.router.navigate().

  • Creare un altro modulo che fornisca una funzione di utilità navigate che chiama internamente Backbone.history.navigate().Questo non è molto diverso da quello che stai facendo, ma lo renderebbe leggermente più modulare e ti impedirà di usare il riferimento globale in ogni momento. Ciò consente anche di modificare l'implementazione interna.

+0

State dichiarando MyNamespace al di fuori dei moduli richiesti? Questo è vicino all'utilizzo dell'oggetto Backbone globale, solo con il mio oggetto, giusto? – MrGrigg

+0

Non sto usando require.js, quindi non si applica nel mio caso. Penso che l'ultimo punto della mia lista sia probabilmente il più vicino all'idioma require.js. – nrabinowitz

+0

Sì, la mia utility per chiamare navigare non è una cattiva idea. Se dovessi farlo, potrei probabilmente fare in modo che la stessa utility presenti il ​​mio router come opzione, forse ciò risolverebbe il tutto. – MrGrigg

8

si potesse fare alla vecchia maniera con window.location.hash :)

window.location.hash = "Edit/1" 

Ecco una soluzione alternativa se non hai bisogno di percorsi espliciti. Quando un'applicazione si avvia crea un oggetto che si estende Backbone Eventi

window.EventDispatcher = _.extend({}, Backbone.Events); 

Poi ovunque in voi applicazione è possibile ascoltare per eventi

EventDispatcher.bind("mymodel:edit", this.editHandler, this); 

E anche da qualsiasi inviare l'evento, data qui sotto sono qualsiasi che params desidera inviare per il lungo viaggio

EventDispatcher.trigger("mymodel:edit", data); 
+0

Ho provato a utilizzare window.location prima di scoprire che potevo utilizzare l'oggetto Backbone globale, ma in realtà non stava attivando i miei eventi, che è probabilmente un problema completamente diverso. – MrGrigg

+0

Se si utilizzano le rotte solo per l'attivazione di eventi (non è necessario che l'URL cambi visibilmente, o che l'utente utilizzi i pulsanti Indietro/Avanti), allora qualcosa che ho capito questo pomeriggio potrebbe essere d'aiuto. Puoi creare un "EventDispatcher" globale che ho aggiunto alla mia risposta sopra. – kreek

+0

Grazie KreeK. Sono andato avanti e indietro con il desiderio che l'URL contasse per questa particolare app. Ho visto almeno un altro esempio simile al tuo dispatcher globale di eventi. Grazie per l'aiuto. – MrGrigg

32

Nel caso in cui qualcun altro stia cercando una soluzione a questo problema come lo ero io, sto postando ciò che ho finito per fare. Se utilizzi il file boilerplate backbone.js, avrai una funzione initialize() in router.js. Ho modificato il mio initialize() funzione simile al seguente:

initialize = function() { 
    var app_router; 
    app_router = new AppRouter(); 

    // Extend the View class to include a navigation method goTo 
    Backbone.View.goTo = function (loc) { 
    app_router.navigate(loc, true); 
    }; 

    Backbone.history.start(); 
}; 

Grazie alla particolare sapore di backbone.js di eredità, questo mi permette permette di chiamare MyView.goTo(location); da qualsiasi delle mie opinioni.

+9

Ho dovuto usare 'Backbone.View.prototype.goTo =' –

+0

puoi usare questo in una vista, in una callback di successo o come faresti a riguardo? Ecco la domanda che mi pongo se vuoi vedere il codice a cui mi riferisco ... http://stackoverflow.com/questions/19472777/clear-localstorage-and-change-the-view-backbone – Lion789

+0

Soluzione molto elegante ! Grazie mille per questo. Ho usato il Backbone.View.prototype per un'altra funzione, ma questo non mi è venuto in mente. – digaomatias

5

Per me, la soluzione con funzione Goto ha lavorato con un leggero cambiamento

Backbone.View.prototype.goTo = function (loc) { 
     appRouter.navigate(loc, true); 
    }; 
3

So che questa domanda è vecchio, ma mi chiedo perché non hai utilizzare require.js al fine di ottenere il router :

define(['./PathToRouter', ], function (router) { 
    return Backbone.View.extend({ 
     template: Handlebars.compile($('#template').html()), 

     events: { 
      'click .edit': 'edit' 
     }, 

     render: function() { 
      //Create and insert the cover letter view 
      $(this.el).html(this.template(this.model.toJSON())); 
      $('#View').html(this.el); 

      return this; 
     }, 

     edit: function() { 
      router.navigate('Edit/' + this.model.id, true); 
     } 
    }); 
}); 
+0

Non so perché non ci ho pensato neanche io. La maggior parte delle cose che ho fatto da allora non hanno richiesto percorsi, quindi non l'ho rivisitato per un po 'di tempo. Sono contento che tu sia intervenuto comunque. – MrGrigg

+2

Nell'esempio sopra, ./PathToRouter non è un'istanza di un router ma una definizione di classe. L'unico metodo statico di un router backbone è estendere senza navigare! – LarZuK

+0

@LarZuK Sono così lontano da questo problema che non ci ho nemmeno pensato, ma sei completamente corretto. – MrGrigg

2

E questo approccio? Poiché la dorsale implementa il modello di modello in tutti i suoi 4 componenti, con un po 'di design è possibile fornire a ciascuna vista un semplice meccanismo di navigazione attraverso il router dell'app senza dover fare alcun riferimento circolare (questo era qualcosa che ho visto in altri post simili, ma cerca di evitarlo).

componente Router, non molto diverso da altri esempi router:

define('Router', ['backbone', ... ], 
     function (Backbone, ...) { 

      var MyRouter = Backbone.Router.extend({ 
       routes: { 
        'viewA': 'viewA', 
        'viewB': 'viewB' 
       }, 

       initialize: function() { 
        ... 
       }; 
      }, 
      viewA: function() { 
       ... 
      }, 

      viewB: function() { 
       ... 
      } 
}); 

return MyRouter; 
}); 

App, crea l'istanza router e spara la prima vista passare questo esempio:

define('App', ['backbone', ... 
], function (Backbone, ...) { 

    function initialize() { 

     //route creation 
     if (!this.routes) 
      routes = new Router(this); 
     //backbone history start 
     Backbone.history.start(); 

     //ViewA navigation, bigbang 
     if (!this.viewA) 
      this.viewA = new ViewA({router: this.routes}); 
     this.viewA.render(); 
    } 

    return { 
     initialize: initialize 
    }; 
}); 

BaseView definizione costruttore di base per tutte le viste e anche un metodo di navigazione:

define('BaseView', ['jquery', 'underscore', 'backbone', ... 
], function ($, _, Backbone, ...) { 
    var BaseView; 

    BaseView = Backbone.View.extend({ 
     id: '...', 

     constructor: function (options) { 
      this.router = options.router; 
      this.model = options.model; 
      Backbone.View.prototype.constructor.call(this); 
     }, 
     initialize: function() { 
      this.template = _.template(tpl); 
     }, 

     events: { 

     }, 
     render: function() { 
      $(this.el).html(this.template()); 

      return this; 
     }, 
     //Provides transparent navigation between views throught the backbonejs 
     //route mechanism 
     navigate: function(pageId) 
     { 
      this.router.navigate(pageId, {trigger: true}); 
     } 
    }); 

    return BaseView; 
}); 

A View esempio, ogni vista si estende dalla base uno invece di spina dorsale, ed eredita il comportamento di base:

define('ViewA', ['jquery', 'underscore', 'backbone', 'BaseView' 
], function ($, _, Backbone, BaseView) { 
    var ViewA; 

    ViewA = BaseView.extend({ 
     id: '...', 

     constructor: function (options) { 
      this._super("constructor"); 
     }, 

     ... 
     foo: function() 
     { 
      ... 

      this.navigate("viewB"); 
     } 
    }); 

    return ViewA; 
}); 

Funziona per me, ed inoltre può essere riutilizzo in altri progetti.

1

per me ho aggiunto un oggetto all'applicazione principale in questo modo;

define(['jquery','underscore','backbone','views/personView','views/peopleView','views/textView'],function($,_,backbone,PersonView,PeopleView,TitleView){ 

    var Router = Backbone.Router.extend({ 
      routes:{ 
       '':'home', 
       'edit/:id':'editPerson', 
       'new':'editPerson', 
       'delete/:id':'deletePerson' 
       } 
      }) 

       var initialize = function(){ 

       var router = new Router(); 

       window.app = { 
        router:router 
        } 

     router.on('route:home',function(){ 


    }) 

      //enable routing using '#'[hashtag] navigation 
     Backbone.history.start(); 

      }; 

      return { 
      initialize:initialize 
      }; 

}); 

e all'interno della vostra vista, si può dire windows.app.router.navigate ({ '', trigger: true}). Non so se lo scope globale è una buona pratica in questo caso, ma ha funzionato per me.

0

Ho una nuova soluzione per il routing dei moduli AMD.

RequireJS Router https://github.com/erikringsmuth/requirejs-router

Questo prende l'approccio di moduli di carico AMD pigri come si navigare a ogni pagina. Con il router Backbone è necessario richiedere tutte le viste come dipendenze in anticipo. Questo carica tutte le tue app Javascript sul primo caricamento della pagina. Il router RequireJS carica i moduli mentre si naviga su ciascuna rotta.

Esempio principale.js utilizzava la tua app

define([], function() { 
    'use strict'; 

    // Configure require.js paths and shims 
    require.config({ 
    paths: { 
     'text': 'bower_components/requirejs-text/text', 
     'router': 'bower_components/requirejs-router/router' 
    } 
    }); 

    // Load the router and your layout 
    require(['router', 'js/layout/layoutView'], function(router, LayoutView) { 
    var layoutView = new LayoutView(); 
    // The layout's render method should draw the header, footer, and an empty main-content section 
    // then load the content section. 
    // render: function() { 
    // this.$el.html(this.template({model: this.model})); 
    // router.loadCurrentRoute(); 
    // } 

    // Configure the router 
    router 
     .registerRoutes({ 
     home: {path: '/', moduleId: 'home/homeView'}, 
     order: {path: '/order', moduleId: 'order/orderView'}, 
     notFound: {path: '*', moduleId: 'notFound/notFoundView'} 
     }) 
     .on('statechange', function() { 
     // Render the layout before loading the current route's module 
     layoutView.render.call(layoutView); 
     }) 
     .on('routeload', function(module, routeArguments) { 
     // Attach the content view to the layoutView's main-content section 
     layoutView.$('#main-content').replaceWith(new module(routeArguments).render().el); 
     }) 
     .init({ 
     // We're manually calling loadCurrentRoute() from layoutView.render() 
     loadCurrentRouteOnStateChange: false 
     }); 
); 
); 
Problemi correlati