5
votes

I am not far from it to get the file upload working with Ember-data. But I do not get the value binding right. Below the relevant code.

This is the App.js

App.LandcodeNewRoute = Ember.Route.extend({
    model: function () {
        return this.store.createRecord('landcode');
    },
    actions: {
        saveLandcode: function () {
            this.currentModel.save();
        }
    }
});


// REST & Model
App.ApplicationAdapter = DS.RESTAdapter.extend({
    namespace: 'api'
});
App.Store = DS.Store.extend({
    adapter: 'App.ApplicationAdapter'
});

App.Landcode = DS.Model.extend({
    code: DS.attr('string'),
    image: DS.attr('string')
});

// Views
App.UploadFile = Ember.TextField.extend({
    tagName: 'input',
    attributeBindings: ['name'],
    type: 'file',
    change: function (e) {
        var reader, that;
        that = this;
        reader = new FileReader();
        reader.onload = function (e) {
            var fileToUpload = e.target.result;

            console.log(e.target.result); // this spams the console with the image content
            console.log(that.get('controller')); // output: Class {imageBinding: Binding,

            that.get('controller').set(that.get('name'), fileToUpload);
        };
        return reader.readAsText(e.target.files[0]);
    }
});

HTML

<script type="text/x-handlebars" data-template-name="landcode/new">
    Code: {{input value=code}}<br />
    Image: {{view App.UploadFile name="image" imageBinding="Landcode.image" }}
    <button {{action 'saveLandcode'}}>Save</button>
</script>

As you can see in the HTML part is that I try to bind the imagecontent to the Landcode model attribute image. Tried it also without capital L.

I think I cant bind the image as such, because it is a custom view object? And also normally it would bind automatically I think. Maybe I am just doing some things twice.

References:

  1. http://emberjs.com/api/classes/Ember.Binding.html

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

  3. File upload with Ember data

  4. How: File Upload with ember.js

  5. http://discuss.emberjs.com/t/file-uploads-is-there-a-better-solution/765

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

2

2 Answers

10
votes

I updated your code to the following:

App.LandcodeNewRoute = Ember.Route.extend({
    model: function () {        
        return this.store.createRecord('landcode');
    },
    actions: {
        saveLandcode: function () {
            this.currentModel.save();
        }
    }
});

// REST & Model
App.ApplicationAdapter = DS.RESTAdapter.extend({
    namespace: 'api'    
});

App.Landcode = DS.Model.extend({
    code: DS.attr('string'),
    image: DS.attr('string')
});

// views
App.UploadFile = Ember.TextField.extend({
    tagName: 'input',
    attributeBindings: ['name'],
    type: 'file',
    file: null,
    change: function (e) {
        var reader = new FileReader(), 
        that = this;        
        reader.onload = function (e) {
            var fileToUpload = e.target.result;
            Ember.run(function() {
                that.set('file', fileToUpload);
            });            
        };
        return reader.readAsDataURL(e.target.files[0]);
    }
});

In the App.UploadFile instead of reference the controller directlly, I set the file property. So you can bind your model property, with the view using:

{{view App.UploadFile name="image" file=image }}

The Ember.run is used to you don't have problems when testing the app.

Please give a look in that jsfiddle http://jsfiddle.net/marciojunior/LxEsF/

Just fill the inputs and click in the save button. And you will see in the browser console, the data that will be send to the server.

1
votes

I found that using attaching a data URI to a model attribute didn't allow files more than about 60k to be uploaded. Instead I ended up writing a form data adapter for ember-data. This will upload all the model data using FormData. Sorry that it's in CoffeeScript rather than JS but it's pasted from my blog post. You can read the whole thing at http://blog.mattbeedle.name/posts/file-uploads-in-ember-data/

`import ApplicationAdapter from 'appkit/adapters/application'`

get = Ember.get

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

`export default FormDataAdapter`