fvisticot
fvisticot

Reputation: 8536

Ember.js: Upload file component

I need to create an Ember component to select a file. My page will include multiple "upload component"

I have read a post trying to implement that: (https://stackoverflow.com/questions/9200000/file-upload-with-ember-data) BUT the UploadFileView is directly linked to the controller. I would like to have something more generic...

I would like to remove the App.StoreCardController.set('logoFile'..) dependency from the view or pass the field (logoFile) from the template...

Any idea to improve this code ?

   App.UploadFileView = Ember.TextField.extend({
    type: 'file',
    attributeBindings: ['name'],
    change: function(evt) {
      var self = this;
      var input = evt.target;
      if (input.files && input.files[0]) {
        App.StoreCardController.set('logoFile', input.files[0]);
      }
    }
});

and the template:

{{view App.UploadFileView name="icon_image"}}
{{view App.UploadFileView name="logo_image"}}

Upvotes: 10

Views: 12354

Answers (4)

Adrian Grzywaczewski
Adrian Grzywaczewski

Reputation: 888

In case of uploading multiple files, you may want to use

{{input type='file' multiple='true' valueBinding='file'}}
                          ^^^^

This is a solution that you would use in normal HTML upload.

Additionally, you can use 'valueBinding' which will allow you to set up an observer against that value in your component.

Upvotes: 1

lpinto.eu
lpinto.eu

Reputation: 2127

EDIT (2015.06): Just created a new solution based on a component. This solution provides an upload button with a preview and remove icon. P.S. The fa classes are Font Awesome

Component handlebars

<script type="text/x-handlebars" data-template-name='components/avatar-picker'>
        {{#if content}}
            <img src={{content}}/> <a {{action 'remove'}}><i class="fa fa-close"></i></a>
        {{else}}
            <i class="fa fa-picture-o"></i>
        {{/if}}

        {{input-image fdata=content}}
</script>

Component JavaScript

App.AvatarPickerComponent = Ember.Component.extend({
    actions: {
        remove: function() {
            this.set("content", null);
        }
    }
});

App.InputImageComponent = Ember.TextField.extend({
    type: 'file',

    change: function (evt) {
        var input = evt.target;
        if (input.files && input.files[0]) {
            var that = this;

            var reader = new FileReader();
            reader.onload = function (e) {
                var data = e.target.result;
                that.set('fdata', data);
            };
            reader.readAsDataURL(input.files[0]);
        }
    }
});

Usage example

{{avatar-picker content=model.avatar}}

Old Answer

I took Chris Meyers example, and I made it small.

Template

{{#view Ember.View contentBinding="foto"}}
    {{view App.FotoUp}}
    {{view App.FotoPreview width="200" srcBinding="foto"}}
{{/view}}

JavaScript

App.FotoPreview= Ember.View.extend({
    attributeBindings: ['src'],
    tagName: 'img',
});


App.FotoUp= Ember.TextField.extend({
    type: 'file',

    change: function(evt) {
        var input = evt.target;
        if (input.files && input.files[0]) {
            var that = this;

            var reader = new FileReader();
            reader.onload = function(e) {
                var data = e.target.result;
                that.set('parentView.content', data);
            }
            reader.readAsDataURL(input.files[0]);
        }
    },
});

Upvotes: 10

Epirocks
Epirocks

Reputation: 502

Marek Fajkus you cannot use JQuery's .serialize, it makes no mention of file uploads in the documentation at JQuery UI docs

However, you could use JQuery Upload Plugin

Actually it does mention it, it says: ". Data from file select elements is not serialized."

Upvotes: 1

Toran Billups
Toran Billups

Reputation: 27399

I completed a full blown example to show this in action

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

Here is the basic handlebars template

<script type="text/x-handlebars" data-template-name="person">
{{view PersonApp.UploadFileView name="logo" contentBinding="content"}}
{{view PersonApp.UploadFileView name="other" contentBinding="content"}}
<a {{action submitFileUpload content target="parentView"}}>Save</a>
</script>

Here is the custom file view object

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 = reader.result;
          self.get('controller').set(self.get('name'), fileToUpload);
        }
        reader.readAsDataURL(input.files[0]);
      }
    }
});

Here is the controller

PersonApp.PersonController = Ember.ObjectController.extend({
  content: null,
  logo: null,
  other: null
});

And finally here is the view w/ submit event

PersonApp.PersonView = Ember.View.extend({
  templateName: 'person',
  submitFileUpload: function(event) {
    event.preventDefault();
    var person = PersonApp.Person.createRecord({ username: 'heyo', attachment: this.get('controller').get('logo'), other: this.get('controller').get('other') });
    this.get('controller.target').get('store').commit();
  }
});

This will drop 2 files on the file system if you spin up the django app

Upvotes: 14

Related Questions