[Ember] Uploads service is undefined #301

Closed
styletabtech opened this Issue Nov 7, 2016 · 12 comments

Projects

None yet

3 participants

@styletabtech
styletabtech commented Nov 7, 2016 edited

Hey @berziiii I'm working on creating a file upload via your instructions (super easy to follow btw thank you!!) and I've run into an issue where 'uploads' is undefined in the route of my new-photo

new-photo/route.js

export default Ember.Route.extend({

  actions: {
    createPhoto(newPhoto) {
        console.log('newPhoto is', newPhoto); 
        console.log(this.get('uploads'));
        return this.get('uploads').newPhotoUpload(newPhoto) // this is where uploads is undefined
       .then(() => this.transitionTo('photos'))
       .catch((error) => console.error(error));
    },
  },
});

I'm not sure if I need to inject this service in a particular way? I've tried doing so in the above file but Ember said no. I'm a little lost on how to go about debugging past this point now that I've identified the problem.

Here's the rest of my code:

new-photo-form/template:

<form enctype="multipart/form-data" id="new-photo-form" {{ action 'create' on='submit' }}>
  <fieldset>
    <legend>Add A Photo</legend>
    <input type="text" class="form-control" name="photo[file_name]" placeholder="Image Name">
    <input type="file" name="photo[photo_upload]" value="Upload Photo">
    <input type="submit" class="btn btn-success" name="submit" value="Add Photo">
  </fieldset>
</form>

new-photo-form/component:

export default Ember.Component.extend({
  newPhoto: {}, // New photo object being constructed from the form

  actions: {
    create() {
      let newPhoto = new FormData(Ember.$('#new-photo-form')); // Ember jQuery to find the form by it's id.
      this.sendAction('create', newPhoto); // Grabs the newPhoto object which has been converted into FormData and sends it up to the route template
      this.set('newPhoto', null); // Resets the newPhoto Object
    }
  }
});

new-photo/template

{{new-photo-form create='createPhoto'}}

photo/uploads/service.js:

export default Ember.Service.extend({
  ajax: Ember.inject.service(),

    newPhotoUpload (newPhoto) {
      return this.get('ajax').post('/photos', {  
        data: newPhoto, // The FormData object which we have called `newPhoto`
        contentType: false,
        processData: false,
      });
     },
});
@berziiii
berziiii commented Nov 7, 2016

You need to inject the uploads service in your route.js file that you're calling this.get('uploads')

@berziiii
berziiii commented Nov 7, 2016

I'll add that to the issue

@styletabtech

Ok I've tried the below but I get the following error:

Uncaught Error: Attempting to inject an unknown injection: 'service:uploads'(…)

I'm investigating this error on the Google but haven't found anything yet. Is this the proper way to inject? I was basing it off of the docs + how auth was injected in the uploads service.

export default Ember.Route.extend({
  uploads: Ember.inject.service(),

  actions: {
    createPhoto(newPhoto) {
        console.log('newPhoto is', newPhoto); 
        console.log(this.get('uploads'));
        return this.get('uploads').newPhotoUpload(newPhoto) 
       .then(() => this.transitionTo('photos')) 
       .catch((error) => console.error(error));
    },
  },
});

I've also tried:

uploads: Ember.inject.service('uploads'),
uploads: Ember.inject.service('photos'),

my file structure is photo > uploads > service.js

@berziiii
berziiii commented Nov 7, 2016 edited

I nested the uploads service inside of photo because symantically, that is where is should go. Try moving the uploads/service.js to app/, on the same level where the ajax directory is and see if that works then.

It is used correctly though as uploads: Ember.inject.service(),

@styletabtech
styletabtech commented Nov 7, 2016 edited

Got it. Ok moving the uploads/service to app/ solved that problem. However, now when I click to add the photo I get the following error:

Error: Ember AJAX Request POST http://localhost:4741/photos returned a 0
Payload (Empty Content-Type)

and rails is saying:

ActionController::ParameterMissing (param is missing or the value is empty: photo):
  app/controllers/photos_controller.rb:57:in `photo_params'
  app/controllers/photos_controller.rb:21:in `create'

my params are as follows:

    def photo_params
      params.require(:photo).permit(:file_name, :user_id, :photo_upload)
    end

new photo form:

<form enctype="multipart/form-data" id="new-photo-form" {{ action 'create' on='submit' }}>
  <fieldset>
    <legend>Add A Photo</legend>
    <input type="text" class="form-control" name="photo[file_name]" placeholder="Image Name">
    <input type="file" name="photo[photo_upload]" value="Upload Photo">
    <input type="submit" class="btn btn-success" name="submit" value="Add Photo">
  </fieldset>
</form>

I'm trying to console log both the uploads service and the formData object, but I'm not totally sure where I should be looking in those to see what's not getting through. Thoughts?

@berziiii
berziiii commented Nov 7, 2016

Right after the create() action where you use new FormData. Can you console log this:

console.log(newPhoto.photo_upload) and see what it returns? Just confirm that you have the photo object when you're about to call the ajax post request. If it's there, then we know it's being passed correctly and that it may be an issue with the object itself.

@berziiii
berziiii commented Nov 7, 2016 edited

Also, make the new FormData like this:

new FormData(document.getElementById('new-movie-form'));

instead of Ember.$('#new-movie-form');. This was to try and use Ember's jQuery feature but it seems not cooperate with new FormData

@styletabtech
styletabtech commented Nov 7, 2016 edited

Confirming that replacing let newPhoto = new FormData(Ember.$('#new-photo-form')); with let newPhoto = new FormData(document.getElementById('new-photo-form')); in the new-photo-form component does the trick!

Originally when I console.logged newPhoto.photo_upload it was undefined but with this change I can successfully upload a new file.

Muchas gracias @berziiii!

@jrhorn424
Member
jrhorn424 commented Nov 8, 2016 edited

instead of Ember.$('#new-movie-form');. This was to try and use Ember's jQuery feature but it seems not cooperate with new FormData

There's nothing wrong with using jQuery to pass something to FormData.

Instead of Ember.$('#new-movie-form'); (why is it movie instead of photo?), use Ember.$('#new-movie-form')[0];. That gets a pure DOM element.

However, don't do it this way.

Some light Googling suggests that in Ember 2, you always have access to the event in an action. So, instead of using Ember.$ to grab an element, why not use event.target with FormData to create what you need?

As a side note, just confirming from your most recent comment:

-let newPhoto = new FormData(Ember.$('#new-photo-form')); with 
+let newPhoto = new FormData(document.getElementById('new-movie-form')); // you meant photo, right?
@jrhorn424
Member
jrhorn424 commented Nov 8, 2016 edited

By default, the action handler receives the first parameter of the event listener, the event object the browser passes to the handler

-- from https://guides.emberjs.com/v2.3.0/templates/actions/

@styletabtech

hi @jrhorn424 I edited my last comment to 'new-photo-form' for clarity, that was a typo on my part. Thanks for the further explanation on Ember jQuery!

@jrhorn424
Member

Awesome.

In case my last comment wasn't clear, this should work:

- let newPhoto = new FormData(document.getElementById('new-photo-form'));
+ let newPhoto = new FormData(event.target);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment