Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File upload with Backbone

I'm using Backbone.js in a Rails app and I need to do file uploads as part of one of the Backbone models.

I don't believe Backbone allows for multi-part file upload out of the box. Has anyone managed to get it working via some plugin or with another external lib? How can I extend Backbone.js to support this?

like image 338
Jey Balachandran Avatar asked Jun 28 '11 00:06

Jey Balachandran


Video Answer


3 Answers

Answering my own question after few months of trial using different methods. My solution is the following (with Rails).

For any form that requires file upload I would set data-remote="true" and enctype="multipart/form-data" and include rails.js and jquery.iframe-transport.js.

Setting data-remote="true" with rails.js allows me to bind to ajax:success and create the Backbone.js model on success.

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:

You should obviously bind ajax:error to handle error cases.

For me, the data is sanitized in the ActiveRecord model, so don't have to worry too much about the eval statement.

$('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

Rails View (create.js.haml):

Using the remotipart gem.

This will handle the case when the form does file uploads with enctype being set, and when it doesn't.

You could choose to call sanitize on your response here.

= remotipart_response do
  - if remotipart_submitted?
    = "eval(#{Yajl::Encoder.encode(@post)});"
  - else
    =raw "eval(#{Yajl::Encoder.encode(@post)});"
like image 164
Jey Balachandran Avatar answered Oct 28 '22 03:10

Jey Balachandran


You may want to check out the jquery.iframe.transport plugin. If you're using rails 3, you can use remotipart instead (it bundles the iframe.transport plugin), which hooks into rails's ujs driver to automatically add support for file upload in ajax requests.

like image 3
Matt Burke Avatar answered Oct 28 '22 01:10

Matt Burke


Resurrecting this one.

As mentioned in previous answers, a multipart/form-data request can be executed via 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
});

It is also important to note that, out-of-the-box, Backbone.sync will merge any options via model.save(null, { /* options here */ }) with the $.ajax instructions.

Your save procedure would look something like:

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 
});
like image 1
jtrumbull Avatar answered Oct 28 '22 03:10

jtrumbull