Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File upload with Ember data

Tags:

ember.js

Can someone provide code examples or documentation on implementing a form with a file field using EmberJS and Ember Data?

I'm familiar with Ember Data already but I'm not sure how to implement file-uploads correctly.

like image 372
Rafael Vega Avatar asked Feb 08 '12 19:02

Rafael Vega


People also ask

How do I upload files to Ember?

ember-cli-file-picker - An addon for ember-cli that provides a component to easily add a filepicker to your ember-cli app. emberx-file-input - A tiny Ember component which does one thing and only: select files beautifully. ember-profile-upload - A simple photo upload component.

How do I automate a file to upload?

To automate this process, there are 2 ways to fill the file upload control: If standard file dialog is used by the web page, upload action can be automated with pure selenium-webdriver. You can call sendKeys() on the file control to fill the file control with file path and then submit form.


4 Answers

Here is part of an ember-data adapter I wrote to do file uploads (same server -not cross domain)

DS.DjangoRESTAdapter = DS.RESTAdapter.extend({
        bulkCommit: false,

        createRecord: function(store, type, record) {
            var root = this.rootForType(type), json = {};

            var data = new FormData();
            data.append('username', record.get('username'));
            data.append('attachment', record.get('attachment'));

            this.django_file_ajax('http://localhost:8000/people/new/', "POST", {
                data: data,
                context: this,
                success: function(pre_json) {
                    json[root] = pre_json;
                    this.didCreateRecord(store, type, record, json);
                }
            });
        },

        django_file_ajax: function(url, type, hash) {
            hash.url = url;
            hash.type = type;
            hash.contentType = false;
            hash.processData = false;
            hash.context = this;

            jQuery.ajax(hash);
        }

    });

})();

It's not IE8 friendly as is because I'm using the "FormData" helper to do multipart file upload but it's a good proof of concept.

Here is the ember-data model to go w/ the above adapter

PersonApp.Person = DS.Model.extend({
  id: DS.attr('number'),
  username: DS.attr('string'),
  attachment: DS.attr('string')
});

Here is the handlebars template

<script type="text/x-handlebars" data-template-name="person">
{{view PersonApp.UploadFileView name="logo_image" contentBinding="content"}}
</script>

Here is the custom ember view

PersonApp.PersonView = Ember.View.extend({
  templateName: 'person'
});

PersonApp.UploadFileView = Ember.TextField.extend({
    type: 'file',
    attributeBindings: ['name'],
    change: function(evt) {
      var self = this;
      var input = evt.target;
      if (input.files && input.files[0]) {
        var reader = new FileReader();
        var that = this;
        reader.onload = function(e) {
          var fileToUpload = e.srcElement.result;
          var person = PersonApp.Person.createRecord({ username: 'heyo', attachment: fileToUpload });
          self.get('controller.target').get('store').commit();
        }
        reader.readAsDataURL(input.files[0]);
      }
    }
});

If you want to see a full blown spike with this in action checkout a multi file upload example I did recently.

https://github.com/toranb/ember-file-upload

like image 195
Toran Billups Avatar answered Oct 02 '22 10:10

Toran Billups


Look at the links below. The first link or blog post contains a link to a working jsfiddle that handles upload with emberjs. Note I didn't write the blog or create the fiddle. But it should solve your issue.

http://chrismeyers.org/2012/06/12/ember-js-handlebars-view-content-inheritance-image-upload-preview-view-object-binding/ - dead link

http://devblog.hedtek.com/2012/04/brief-foray-into-html5-file-apis.html

like image 21
brg Avatar answered Oct 02 '22 09:10

brg


It's fairly simple, the general steps are:

  1. Hook up an input within Ember.
  2. Read the data from the local file specified in the input element.
  3. Encoded the data as base64.
  4. Set the value of your ember-data model to the base64 string.
  5. On the server, decode the base64 string and voila, your binary file data is on the server.

It should be noted though that base64 encoding large files has performance issues, but for smaller images or text it won't be a problem.


You could also send the file 'outside' of Ember Data, and push the response (such as a JSON payload representing a model) into the store via pushPayload. If so, FormData or other methods in XHR2 can be used.

Read more about client-side manipulation of files here: http://www.html5rocks.com/en/tutorials/file/dndfiles/

Read more about XHR2 and FormData for file uploads here: http://www.html5rocks.com/en/tutorials/file/xhr2/

like image 21
sandstrom Avatar answered Oct 02 '22 09:10

sandstrom


I tried a few different solutions and ended up writing a FormData adapter and a File transform. Then any model that needs to upload file data can just use the FormDataAdapter and define the file attributes as type "file":

app/transforms/file.coffee

FileTransform = DS.Transform.extend
  serialize: (jsonData) ->
    jsonData

  deserialize: (externalData) ->
    externalData

app/models/user.coffee

User = DS.Model.extend
    avatar: DS.attr('file')

app/adapters/form_data.coffee

get = Ember.get;

App.FormDataAdapter = ApplicationAdapter.extend
  ajaxOptions: (url, type, hash) ->
    hash = hash || {}
    hash.url = url
    hash.type = type
    hash.dataType = 'json'
    hash.context = @

    if hash.data and type != 'GET' and type != 'DELETE'
      hash.processData = false
      hash.contentType = false
      fd = new FormData()
      root = Object.keys(hash.data)[0]
      for key in Object.keys(hash.data[root])
        if hash.data[root][key]
          fd.append("#{root}[#{key}]", hash.data[root][key])

      hash.data = fd

    headers = get(@, 'headers')
    if headers != undefined
      hash.beforeSend = (xhr) ->
        for key in Ember.keys(headers)
          xhr.setRequestHeader(key, headers[key])

    hash

app/adapters/user.coffee

UserAdapter = FormDataAdapter.extend()

Sorry about the CoffeeScript, but it's pasted from this blog post: http://blog.mattbeedle.name/posts/file-uploads-in-ember-data/. You can read a more detailed description there. This solution should probably be combined with a HTML5 FileReader input to enable image previews and client side file type validation.

like image 28
Matt Beedle Avatar answered Oct 02 '22 09:10

Matt Beedle