Image (File) Input Component for Ember.js

In order to enable a great user experience I wanted to show the user’s newly selected profile picture in one of our clients web apps right after she choose the desired file in her browser’s file picker dialog.

Unfortunately this is not yet as easy as a simple {% raw %}<input type="file" file={{file}}>{% endraw %}.

Having found this pure JavaScript implementation of similar behaviour on HTML5 Rocks, I set out to port it to Ember.

Since I was not able to find any recent Ember-compatible code solving this problem, I created my own version using the latest Ember conventions: a component.

app/components/file-input.js: {% highlight javascript linenos %} import Ember from ‘ember’;

export default Ember.TextField.extend({ type: ‘file’, change: function(e) { let self = this;

var inputFiles = e.target.files;
if (inputFiles.length < 1) {
  return;
}

let inputFile = inputFiles[0];

let fileInfo = {
  name: inputFile.name,
  type: inputFile.type || 'n/a',
  size: inputFile.size,
  date: inputFile.lastModifiedDate ?
        inputFile.lastModifiedDate.toLocaleDateString() : 'n/a',
};

var fileReader = new FileReader();

fileReader.onload = function(e) {
  let fileReader = e.target;
  fileInfo.dataURL = fileReader.result;

  self.sendAction('fileChanged', fileInfo);
};

let firstFile = e.target.files[0];
fileReader.readAsDataURL(firstFile);

}, }); {% endhighlight %}

app/components/image-input.js: {% highlight js linenos %} import Ember from ‘ember’;

export default Ember.Component.extend({ file: null, actions: { fileSelectionChanged: function(file) { this.set(‘file’, file) }, }, }); {% endhighlight %}

app/templates/components/image-input.hbs: {% highlight html linenos %} {% raw %} Image Input

{{#if file}}

  • Name: {{file.name}}
  • Type: {{file.type}}
  • Size: {{file.size}} bytes
  • Last modified: {{file.date}}
{{/if}}

{{ file-input fileChanged=“fileSelectionChanged”}} {% endraw %} {% endhighlight %}

Now usage is as easy as {% raw %}{{image-input}}{% endraw %}!

The result looks like this: