0

I'm having trouble with uploading images in Ember.js

I have a form to create a user :

<div class="container">
<form onsubmit={{action "createUser"}} enctype="multipart/form-data">
  <div class="form-group">
    <label for="firstName">First name: </label>
    {{input type="text" class="form-control" id="firstName" required="true" value=firstName}}
  </div>
  <div class="form-group">
    <label for="lastName">Last name: </label>
    {{input type="text" class="form-control" id="lastName"  required="true" value=lastName}}
  </div>
  <div class="form-group">
    <label for="age">Age: </label>
    {{input type="number" class="form-control" id="age"  required="true" value=age}}
  </div>
  <div class="form-group">
    <label for="job">Job: </label> 
    {{input type="text" class="form-control" id="job"  required="true" value=job}}
  </div>
  <div class="form-group">
    <label for="image">Picture: </label> 
    {{input type="file" class="form-control" id="image" value=image}}
  </div>
  <button type="submit" class="btn btn-info">Create</button>
</form>

I know I should encode images in base64 but I have no idea how to do that since I've never done it before.

And in the view, this is how I'm trying to get the image (I know this is not what I should do but I don't know how to do it) :

<div class="container">
  <h1>{{model.firstName}} {{model.lastName}}</h1>
  <p>Age: {{model.age}} years old</p>
  <p>Job: {{model.job}}</p>
  <img src="{{model.image}}" alt="img" id="image">
</div>

Any ideas, suggestions, help please ?


EDIT :

actions: {
  createUser(event) {
    event.preventDefault();
    let user = this.store.createRecord('user', {
      firstName: this.firstName,
      lastName: this.lastName,
      age: this.age,
      job: this.job,
      image: this.image
    });
    user.save().then (() => {
      this.transitionToRoute('user', user.id);
    });
  }
}
rinold simon
  • 2,782
  • 4
  • 20
  • 39
Elena
  • 55
  • 10
  • can you show your `createUser` action? How does your backend expect your image? – Lux Mar 30 '19 at 04:13
  • I added my createUser action in the original post. I have no backend actually, I'm working with mirage and I don't need to save the data I'm creating. – Elena Mar 30 '19 at 09:53
  • mirage is only for testing. It wouldn't be useful to not save what you create in the end, right? And while mirage useful, you still need an idea how your actual backend should work. For images I would usually just put an URI in the model. You've mentioned something about base64, but did not elaborate. could you please explain you you come to base64, and what you want with it? – Lux Mar 30 '19 at 13:20
  • Well that‘s just an exercice and I don’t need back end so... but if I had to, what would you suggest to use? And basically someone explained to me that I should encode my images and put the result in a string, that’s where I’m stuck – Elena Mar 31 '19 at 15:48

2 Answers2

2

Make use of ember-file-upload addon. The addon takes care in encoding them as a Base64 data url. In your case follow the below steps,

hbs form page:

<form onsubmit={{action 'createUser'}}>
  <div class="form-group">
    <label for="firstName">First name: </label>
    {{input type="text" class="form-control" id="firstName" required="true" value=firstName}}
  </div>

  ...
  //other input fields
  ...

  {{#file-upload name="avatar"
                 accept="image/*"
                 onfileadd=(action 'setAvatar')}}

    // preview image before uploading
    {{#if avatar}}
      <img src={{avatar}}
      <a id="upload-avatar">Add a photo</a>
    {{else}}
      <a id="upload-avatar">Add a photo</a>
    {{/if}}

  {{/file-upload}}
  <button type="submit">Create</button>
</form>

hbs view page:

<div class="container">
  <h1>{{model.firstName}} {{model.lastName}}</h1>
  <p>Age: {{model.age}} years old</p>
  <p>Job: {{model.job}}</p>
  <img src={{model.image}} alt="img" id="image">
</div>

js:

import Controller from '@ember/controller';

export default Controller.extend({
  avatarFile: null,
  actions: {
    createUser(event) {
      event.preventDefault();
      // upload file to backend
      let file = this.get('avatarFile');
      // make a api call to the url `/upload` (modify the url as you wish)
      file.upload('/upload').then((response) => {
        // save user model once the image is been uploaded successfully to the server
        let user = this.store.createRecord('user', {
          firstName: this.firstName,
          ...
          // get the image_url from backend response
          image: response.image_url
        });
        user.save().then((response) => {
          // get the user_id in response
          this.transitionToRoute('user', response.user_id);
        });
      });
    },
    setAvatar(file) {
      this.set('avatarFile', file);

      // Set the URL so we can see a preview
      file.readAsDataURL().then((url) => {
        this.set('avatar', url);
      });
    }
  }
});

You can refer to the entire documentation here

rinold simon
  • 2,782
  • 4
  • 20
  • 39
  • Thanks for your help :) I get this error message when I try to create a new user "Uncaught TypeError: file.upload is not a function", any idea why ? – Elena Apr 01 '19 at 14:18
  • make sure `this.set('avatarFile', file);` line is present in `setAvatar` actions ? – rinold simon Apr 01 '19 at 14:31
  • please follow this doc `http://adopted-ember-addons.github.io/ember-file-upload/docs/integration` – rinold simon Apr 01 '19 at 15:04
  • Still the same error, even after reading the doc about 30 times haha. I really can't figure it out ! Thanks for asking though – Elena Apr 02 '19 at 09:22
1

Replace

{{input type="file" class="form-control" id="image" value=image}}

with

<input type="file" class="form-control" id="image" onchange={{action "uploadFile"}}/>
<br> Chosen image is <br>
<img src={{image}} />

This will trigger the uploadFile action when the image is chosen. In your js file, add the action as ,

actions: {
  uploadFile: function(event) {
    var self = this;
    const reader = new FileReader();
    const file = event.target.files[0];
    let imageData;

    reader.onload = function(){
      imageData = reader.result;
      self.set('image', imageData);
    };

    if (file) {
      reader.readAsDataURL(file);
    }
  }
}

Source : https://stackoverflow.com/a/40370830/2824131

acid_srvnn
  • 693
  • 8
  • 15