2011-06-28 22 views
29

Sto utilizzando Backbone.js in un'app Rails e devo caricare file come parte di uno dei modelli Backbone.Caricamento file con Backbone

Non credo che Backbone consenta il caricamento di file in più parti fuori dalla scatola. Qualcuno è riuscito a farlo funzionare tramite qualche plugin o con un'altra lib esterna? Come posso estendere Backbone.js per supportare questo?

risposta

20

Rispondere alla mia domanda dopo alcuni mesi di prova con metodi diversi. La mia soluzione è la seguente (con Rails).

Per qualsiasi modulo che richiede il caricamento di file, impostare data-remote="true" e enctype="multipart/form-data" e includere rails.js e jquery.iframe-transport.js.

L'impostazione data-remote="true" con rails.js consente di eseguire il binding a ajax:success e creare il modello Backbone.js in caso di successo.

HTML:

<form action="/posts.js" method="post" data-remote="true" enctype="multipart/form-data"> 
    <input type="text" name="post[message]" /> 
    <input type="file" name="post[file]" /> 
    <button>Submit</button> 
</form> 

JavaScript:

Si dovrebbe ovviamente legarsi ajax:error per gestire i casi di errore.

Per me, i dati vengono sterilizzate nel modello ActiveRecord, quindi non c'è bisogno di preoccuparsi troppo per la dichiarazione eval.

$('form').bind('ajax:success', function(event, data) { 
    new Model(eval(data)); // Your newly created Backbone.js model 
}); 

Rails controller:

class PostsController < ApplicationController 
    respond_to :js 

    def create 
    @post = Post.create(params[:post]) 
    respond_with @post 
    end 
end 

rotaie vista (create.js.haml):

Utilizzo della gemma remotipart.

Ciò gestire il caso in cui il modulo fa upload di file con enctype stato impostato, e quando lo fa non è.

È possibile scegliere di chiamare sanitize sulla risposta qui.

= remotipart_response do 
    - if remotipart_submitted? 
    = "eval(#{Yajl::Encoder.encode(@post)});" 
    - else 
    =raw "eval(#{Yajl::Encoder.encode(@post)});" 
+0

Neat. Due domande però. Nel tuo controller, hai intenzione di fare 'Post.new (params [: post])' o in realtà intendevi 'Post.create (params [: post])'? E in secondo luogo, dove posizioneresti il ​​callback '$ ('form'). Bind ('ajax: success')', in una classe Backbone.View per il modulo dato? Grazie! –

+0

Grande cattura, errore di battitura da parte mia. Dovrebbe essere "Post.create". Inserirò $ ('form'). Bind ('ajax: success') nella mia vista Backbone che esegue il rendering del modulo. –

+0

Aggiungi data-type = "json" al modulo ed è possibile rimuovere la vista. – maletor

0

Penso che tu abbia frainteso il modo in cui funziona la spina dorsale. Backbone è una libreria MVC per javascript, non un server web. I caricamenti dei file sono negoziati tra il browser dei client e il tuo server. Backbone è solo il livello intermedio che ti aiuta a organizzare e presentare i dati in modo facile e conveniente.

Detto questo, ciò che è necessario fare per associare un file al modello è 1) gestire il caricamento con le guide e quindi 2) archiviare il nome e il percorso del file in una stringa all'interno del modello.

Quindi, ecco la parte upload di file:

http://khamsouk.souvanlasy.com/articles/ajax-file-uploads-in-rails-using-attachment_fu-and-responds_to_parent

Una volta che si ottiene indietro l'oggetto list_item, si sarebbe solo creare un nuovo campo nel modello e memorizzare list_item.filename e asset_path(list_item).

Spero che questo aiuti.

+0

Inoltre, ecco un link ad una domanda simile SO per Django http://stackoverflow.com/questions/6092596/backbone-js-link-file -to-modello – Swift

3

È possibile controllare il plug-in jquery.iframe.transport. Se si utilizzano i binari 3, è possibile utilizzare invece remotipart (che raggruppa il plug-in iframe.transport), che si aggancia al driver ujs delle rotaie per aggiungere automaticamente il supporto per il caricamento di file nelle richieste Ajax.

+0

Grazie Matt. Ho finito per usare esattamente quello che hai descritto qualche tempo fa ma non sono riuscito ad aggiornare questa domanda. –

0

Se non ti dispiace di rompere la compatibilità a ritroso, è possibile usufruire di XHR2 and FormData

E 'semplice come sembra:

var data = new FormData($('form.someForm').get(0)); 
$.ajax('http://*****.com', { 
    type:'POST', 
    data: data, 
    processData: false, 
    contentType: false // it automaticly sets multipart/form-data; boundary=... 
}); 
1

Resurrecting questo.

Come accennato nelle risposte precedenti, una richiesta multipart/form-data possono essere eseguite tramite jQuery.ajax:

var formData = new FormData(); 
var input = document.getElementById('file'); 

formData.append('file', input.files[0]); 

$.ajax({ 
    url: 'path/to/upload/endpoint' 
    type:'POST', 
    data: formData, 
    processData: false, 
    contentType: false 
}); 

E 'anche importante notare che, out-of-the-box, Backbone.sync si fonderanno qualsiasi opzioni tramite model.save(null, { /* options here */ }) con le istruzioni $.ajax.

tuo salvare procedura sarebbe simile:

var model = new Model({ 
    key: 'value' 
}); 
var input = document.getElementById('file'); 
var formData = new FormData(); 

_.each(model.keys(), function (key) { // Append your attributes 
    formData.append(key, model.get(key)); 
}); 

formData.append('file', input.files[0]); // Append your file 

model.save(null, { 
    data: formData, 
    processData: false, 
    contentType: false 
});