title: AJAX Image upload with backbone.js node.js and express
body: <p>So I have been trawling the net for a day now trying to find a complete example of how to upload an image along with a normal POST (create) request from a backbone model.  So after some initial digging around I discovered the <code>FileReader</code> api in HTML5 - After some testing I had this working great outside backbone by creating a  <code>XMLHttpRequest()</code></p>
  
  <p>The problem im now trying to solve is how can I make bacbone send the FILES data along with the POST request like you would experience in a normal multipart form work flow.  Im pretty new to backbone so please forgive any obvious errors. Heres what I have so far.</p>
  
  <h1>model</h1>
  
  <pre><code>define(                                                                                                                                                
      [                                                                                                                                                  
          'backbone'                                                                                                                                     
      ],                                                                                                                                                 
  
      function (Backbone) {                                                                                                                              
          var Mock = Backbone.Model.extend({                                                                                                             
              url: '/api/v1/mocks',                                                                                                                      
              idAttribute: '_id',                                                                                                                        
  
              readFile: function(file){                                                                                                                  
                  var reader = new FileReader();                                                                                                         
                  self = this;                                                                                                                           
  
                  reader.onload = (function(mockFile){                                                                                                   
                      return function(e){                                                                                                                
                          self.set({filename: mockFile.name, data: e.target.result});                                                                    
                      };                                                                                                                                 
                  })(file);                                                                                                                              
  
                  reader.readAsDataURL(file);                                                                                                            
              }                                                                                                                                          
          });                                                                                                                                            
  
          return Mock;                                                                                                                                   
      }                                                                                                                                                  
  );
  </code></pre>
  
  <h1>view</h1>
  
  <pre><code>define(
      [
          'jquery',
          'backbone',
          'underscore',
          'text!../templates/create_mock-template.html',
          'models/mock',
          'collections/mocks'
      ],
  
      function ($, Backbone, _, createMockTemplate, Mock, mocksCollection) {
          var CreateMockView = Backbone.View.extend({
              template: _.template(createMockTemplate),
  
              events: {
                  'submit form': 'onFormSubmit',
                  'click #upload-link': 'process',
                  'change #upload': 'displayUploads'
              },
  
              initialize: function () {
                  this.render();
                  return this;
              },
  
              render: function () {
                  this.$el.html(this.template);
              },
  
                          process: function(e){
                                  var input = $('#upload');
                                  if(input){
                                          input.click();
                                  }
                                  e.preventDefault();
                          },
  
                          displayUploads: function(e){
                                  // Once a user selects some files the 'change' event is triggered (and this listener function is executed)
                                  // We can access selected files via 'this.files' property object.
  
                                  var formdata = new FormData();
                                  var img, reader, file;
                                  var self = this;
  
                                  for (var i = 0, len = e.target.files.length; i &lt; len; i++) {
                                          file = e.target.files[i];
  
                                          if (!!file.type.match(/image.*/)) {
                                                  if (window.FileReader) {
                                                          reader = new FileReader();
                                                          reader.onloadend = function (e) { 
                                                                  self.createImage(e.target.result, e);
                                                          };
                                                          self.file = file;
                                                          reader.readAsDataURL(file);
                                                  }
                                          }   
                                  }
                          },
  
                          createImage: function(source, fileobj) {
                                  var image = '&lt;img src="'+source+'" class="thumbnail" width="200" height="200" /&gt;'
                                  this.$el.append(image);
                          },
  
              onFormSubmit: function (e) {
                  e.preventDefault();
  
                  // loop through form elements
                  var fields = $(e.target).find('input[type=text], textarea');
                  var data = {};
  
                  // add names and vlaues to data object
                  $(fields).each(function(i, f) {
                      data[$(f).attr('name')] = $(f).attr('value');
                  }); 
  
                  // create new model from data
                  var mock = new Mock(data);
  
                  // this should set the filename and data attributes on the model???
                  mock.readFile(this.file);
  
                  // save to the server
                  mock.save(null, {
                      wait: true,
                      error: function(model, response) {
                          console.log(model)
                      },
                      success: function(model, response) {
                          mocksCollection.add(model);
                          console.log(model, response);
                      }
                  });
              },
          });
  
          return CreateMockView;
      }
  );
  </code></pre>
  
  <p>I totally appreciate this may all be a bit hand wavey, its more a proof of concept than anything else and a good chance to learn backbone too.  So the crux of my question is this</p>
  
  <ul>
  <li>When the request is sent by backbone to the api why arent I seeing the data and filename attrs in the request to the node/express server</li>
  <li>Is what im trying to do even possible, I basically thought i'd be able to read the data attr and create and image on the server?</li>
  <li>Is there a way to perhaps overide the sync method on the Mock model and create a properly formed request where POST and FILES are correctly set.</li>
  </ul>
  
  <p>Im sure this is possible but I just cant seem to find the bit of info I need to plough on and get this working.!</p>
  
  <p>Hope someone can help!</p>
  
  <p>CHEERS</p>
  
  <h1>edit</h1>
  
  <p>Just wanted to provide a bit more info as by my understanding and some brief chats on the document cloud irc channel this should work.  So when I call</p>
  
  <pre><code>mock.readFile(this.file)
  </code></pre>
  
  <p>the fileName and data attributes dont seem to get set.  In fact a console log here dosent even seem to fire so im guessing this could be the problem.  I would be happy with this approach to basically build up the Image on the node end based on the value of data and fileName.  So why arent these properties being set and passed along in the post request to the api?</p>