EmberDroplet
EmberDroplet copied to clipboard
Override uploadAllFiles?
How can I hook into the file upload process. Can I override an action on the controller to manage what is done with the response? Perhaps a callback on the controller didUploadAllFiles
?
@theworkerant I think what you will need to do is something like this. (I'm really new to this, so forgive me if I'm wrong.)
This will go in the controller where you are using the DropletController mixin:
uploadedSomeFiles: function uploadedSomeFiles() {
// this gets fired once all the files have uploaded
var files = this.get('uploadedFiles');
files.forEach(function(file) {
// do something here with the files
});
}.observes('files.length', '[email protected]')
However, in my case, the file
object that is returned wasn't the object returned from my API. Perhaps I was doing something wrong. What I wanted to do was render uploaded images back to the view once they had uploaded and been created by my Rails API. In the end, what I had to do was actually modify the mixin code itself (not best practice, I know) like this:
ember-droplet-mixin.js (starting at app. line 178):
request.send(formData);
request.onload = function() {
// Here I load my model
var media = App.Media.find();
// as you probably know, within onload you have access to responseText which in my case was
// the JSON object that my Rails API was rendering
$.each($.parseJSON(request.responseText), function(idx, obj) {
media.pushObject(obj);
});
}
return deferred.promise();
Perhaps there's a better way to do this, but you'll need to inspect the object returned by 'uploadedFiles' yourself to see if that is what you need or if you perhaps need the responseText.
This is what we do in our app:
var FilesUploadController = Ember.Controller.extend(DropletController, {
uploadAllFiles: function() {
var self = this;
$.when(self._super()).then(function(data){
// do whatever you want here
// data will contain the json response from your server
});
}
});
@g-cassie I modified my app to use this code, but it never gets fired for some reason. Here's the full code:
App.MediaController = Ember.Controller.extend(DropletController, {
dropletUrl: 'http://localhost:3000/images',
useArray: true,
uploadAllFiles: function() {
// this never fires
console.log('Fired!');
var self = this;
$.when(self._super()).then(function(data){
var media = App.Media.find();
$.each($.parseJSON(data), function(idx, obj) {
media.pushObject(obj);
console.log(data);
});
});
},
actions: {
deleteImage: function (media) {
media.deleteRecord().fail( function(e) {
App.displayError(e);
});
console.log("delete!");
}
}
});
Sorry, uploadAllFiles
needs to go in the actions
object.
var FilesUploadController = Ember.Controller.extend(DropletController, {
actions:{
uploadAllFiles: function() {
var self = this;
$.when(self._super()).then(function(data){
// do whatever you want here
// data will contain the json response from your server
});
}
}
});
Great, @g-cassie, that worked like a charm. My original problem was, that the data being returned wasn't my actual objects being rendered back from my Rails API, but data
is.
Don't know if this will help anyone, but here's my code for others following along:
actions:{
uploadAllFiles: function() {
var self = this;
$.when(self._super()).then(function(data){
var media = App.Media.find();
// $.parseJSON(data) is no longer necessary, since data has apparently already
// been converted to an object which Ember.js knows how to handle.
$.each(data, function(idx, obj) {
media.pushObject(obj);
});
media.reload();
});
}
}
I need to reload()
my media model, otherwise the deleteImage
action on each individual file doesn't work for some reason until I refresh the page. It seems like a lot of overhead and I'm not sure if there's a better way to do this, so I'm open to suggestions.
Looks like you are using the old version ember-data which I know very little about so unfortunately I can't really offer any guidance.
I'm actually using ember-model, but have pretty much hobbled together stuff I've found on stackoverflow. Thanks anyway. I suppose, if I was doing it the regular (non-AJAX way), I would upload the files and refresh the entire page (i.e., query the database for the entire model) again, so perhaps this method isn't so much more 'expensive' than it should be.
You've helped me a lot, and I hope the OP has been able to glean something from this. ;-) @theworkerant did this help?
@g-cassie Yea that looks like just what I wanted. Thanks.
@reblevins We use ember-data and it just isn't sophisticated enough to do something like this so in this kind of situation we end up tacking on a reload api call, even though the file upload response actually contains all the information the app needs. I don't really want to spend a bunch of time hacking around this to cut out an api call when (hopefully) an ember-data release is just around the corner.
@reblevins thanks! I've been away for the weekend, so was unable to properly reply; although it seems as you though you folks have figured everything out.
However, Is there something I should include into Droplet? As $.when(self._super())
doesn't seem to be the most enlightening of code. I didn't want to do much with the API response, because that could be anything depending on your API.
As per OP's request, I could add a didUploadFiles
of sorts, but that would simply pass through the latest additions into the files
array.
@Wildhoney :+1:
I love callbacks. didUploadFiles
seems like it should exist for an Ember ... "plugin" (?) and couldn't hurt much (possibly a naive statement).
Folks! Please let me know if this change is any good :+1:
Great, it fired and the images got added to the page, but I got this error:
Uncaught TypeError: Cannot read property 'length' of undefined jquery.js?body=1:359
jQuery.extend.each jquery.js?body=1:359
App.ImagesController.Ember.Controller.extend.didUploadFiles images.js?body=1:11
Ember.tryInvoke ember.js?body=1:1354
(anonymous function) ember-droplet-mixin.js?body=1:167
Here's my controller code:
didUploadFiles: function(response) {
var images = this.store.findAll('image');
$.each(response, function(idx, obj) {
images.pushObject(obj);
});
images.save();
}
Apparently, this: $.each(response, function(idx, obj) {
is the offending bit of code in my controller so it may not have anything to do with your code.
EDIT:
console.log(response);
returned undefined
Oops! Please try again.
Yes, that did the trick! console.log(data);
returns the array of JSON objects from my API.
And, actually, kind of annoying, but all that code I was using just to update the view (which took me more than a week to figure out), was unnecessary. I was using ember-model and now I switched back to Ember Data and all I need is this:
didUploadFiles: function(response) {
var images = this.store.findAll('image');
}
That reloads the images
and the view updates automatically. So, thanks for the useArray
and didUploadFiles
, that did the trick. Someday, I'm going to write a tutorial chronicling all of my experiences with Rails 4 + Carrierwave + Ember, etc...
@reblevins If you ever do write that Rails 4 + Carrierwave + Ember tutorial, I'd be very interested in reading it! :+1: