2012-02-03 22 views
5

posso mancare completamente qualcosa qui, ma ho il seguente:Ottenere backbone.js per eseguire una funzione dopo aver creato una raccolta?

  • un modello che racchiude in sé 'tutti' i dati (tutti JSON caricati da un URL)
  • il modello ha uno (o più) collezioni quale è istanziare con i dati che riceve costruzione
  • po 'di codice che ho voglia di correre sulla collezione quando viene inizializzato i dati e caricato

la mia domanda riguarda la collezione composta. Potrei farlo al di fuori dell'ambito della Collezione, ma preferirei incapsularlo (altrimenti qual è il punto di renderlo una 'classe' con un inizializzatore, ecc.).

  1. ho pensato che avrei potuto mettere che il codice nella funzione initialize(), ma che corre prima che il modello è stato compilato, quindi non ho accesso ai modelli che compongono la collezione (this.models è vuota).

  2. Poi ho pensato di poter associare a un evento, ma nessun evento viene attivato dopo l'inizializzazione. Lo sarebbero se caricassi la collezione con un fetch dal proprio endpoint, ma non lo sto facendo, sto inizializzando la raccolta da dati preesistenti.

La mia domanda: Come arrivare inizializzare il codice da eseguire sul Collezione subito dopo che è stato inizializzato con dati (vale a dire this.models non è vuoto).

È possibile farlo senza dover inserire il codice "esterno"?

Ok ecco il codice demo, forse questo spiegherà meglio le cose.

var Everything = Backbone.Model.extend({ 
    url: "/static/data/mydata.json", 
    parse: function(data) 
    { 
     this.set("things", new Things(data.things, {controller: this})); 
    } 
}); 

var Thing = Backbone.Model.extend({ 
}); 

var Things = Backbone.Collection.extend({ 
    model: Thing, 
    initialize: function(data, options) 
    { 
     // HERE I want access to this.models. 
     // Unfortunately it has not yet been populated. 
     console.log("initialize"); 
     console.log(this.models); 
     // result: [] 

     // And this event never gets triggered either! 
     this.on("all", function(eventType) 
     { 
      console.log("Some kind of event happend!", eventType); 
     }); 
    } 
}); 

var everything = new Everything(); 
everything.fetch(); 

// Some manual poking to prove that the demo code above works: 

// Run after everything has happened, to prove collection does get created with data 
setTimeout(function(){console.log("outside data", everything.get("things").models);}, 1000); 
// This has the expected result, prints a load of models. 


// Prove that the event hander works. 
setTimeout(function(){console.log("outside trigger", everything.get("things").trigger("change"));}, 1000); 
// This triggers the event callback. 

risposta

7

Purtroppo per voi la collezione viene impostata con dati solo dopo che è stato inizializzato correttamente prima e modelli vengono ripristinate utilizzando silent: true bandiera che significa che l'evento non si innescherà.

Se si desidera veramente utilizzarlo, è possibile imbrogliare un po 'ritardando l'esecuzione di qualsiasi cosa si desideri fare al prossimo ciclo di eventi del browser utilizzando setTimeout (..., 0) o il metodo di sottolineatura defer.

initialize: function(data, options) { 

    _.defer(_.bind(this.doSomething, this)); 
}, 

doSomething: function() { 

    // now the models are going to be available 
} 
+0

Speravo di eseguire la costruzione della raccolta in modo sincrono (quindi, ad esempio, potrebbe essere utilizzato nella riga successiva di "Everything.parse"). Ovviamente differire non lo farebbe. Potrei dover spostare la logica fuori dalla collezione. Forse una richiesta di modifica a Backbone.js ... – Joe

+0

L'utilizzo di "differimento" risulta ideale se si desidera installare EventListener in webCGM. Il diagramma webCGM viene caricato come oggetto indipendente e inizia la vita come immagine stupida. Devi dirlo esplicitamente per iniziare a inviarti gli eventi, che puoi poi reindirizzare all'infrastruttura backbone. Sospetto che la stessa tecnica possa essere utilizzata per interagire con altri plug-in (SVG/PDF ecc.), Molti dei quali non funzionano bene nel broswer. –

0

Scavando questa una vecchia domanda. Ho avuto un problema simile e ho avuto qualche aiuto per creare questa soluzione:

Estendendo la funzione set possiamo sapere quando i dati della collezione sono stati convertiti in modelli reali. (Set viene chiamato da .add e .reset, il che significa che viene chiamato durante la funzione principale che istanzia la classe Collection AND dal fetch, indipendentemente da reset o set nelle opzioni di recupero .Un tuffo nella sorgente annotata backbone e seguendo il flusso di funzioni aiutato qui)

In questo modo possiamo avere il controllo su quando/come ricevere una notifica senza l'hacking del flusso di esecuzione.

var MyCollection = Backbone.Collection.extend({ 
    url: "http://private-a2993-test958.apiary-mock.com/notes", 
    initialize: function() { 
    this.listenToOnce(this, 'set', this.onInitialized) 
    }, 

    onInitialized:function(){ 
    console.log("collection models have been initialized:",this.models) 
    }, 

    set: function(models,options){ 
    Backbone.Collection.prototype.set.call(this, models, options); 
    this.trigger("set"); 
    } 
}) 

//Works with Fetch! 
var fetchCollection= new MyCollection() 
fetchCollection.fetch(); 

//Works with initializing data 
var colData = new MyCollection([ 
     {id:5, name:'five'}, 
     {id:6, name:'six'}, 
     {id:7, name:'seven'}, 
     {id:8, name:'eight'} 
    ]) 

//doesn't trigger the initialized function 
colData.add(new Backbone.Model({id:9,name:'nine'}; 

Nota: se noi non usare .listenToOnce, allora avremo anche ottenere onInitialized chiamato ogni volta che un modello viene aggiunto o modificato nella collezione pure.

Problemi correlati