Skip to content

Instantly share code, notes, and snippets.

@deanmraz
Last active August 29, 2015 14:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deanmraz/6b7f0bce210de36e2c03 to your computer and use it in GitHub Desktop.
Save deanmraz/6b7f0bce210de36e2c03 to your computer and use it in GitHub Desktop.
Ember Component - From jQuery to Ember
<div {{bind-attr class=":zone showZone::hidden errors:with-notify"}}>
<div class="text">
<button class="btn btn-primary">Browse Computer</button><br>
<p class="sub-text">or drag files here</p>
</div>
<input type="file" name="imageLibraries" multiple>
</div>
{{#unless processing}}
<div class="text completed">
{{#if done}}
<div class="alert alert-info">
<b>Upload Completed.</b> <a {{action addMore}}>Click here to add more</a>.
</div>
{{/if}}
{{#if errors}}
<div class="alert alert-danger">
<b>Upload Failed!</b> <a {{action addMore}}>Click here to try again</a>.
</div>
{{/if}}
</div>
{{else}}
{{#unless showZone}}
<div class="progress">
<div {{bind-attr style='cssStyle' class=":progress-bar processing:progress-bar-striped processing:active done:progress-bar-success errors:progress-bar-danger"}}>
{{#if done}}Completed{{/if}}
{{#if errors}}Errors{{/if}}
</div>
</div>
{{/unless}}
{{/unless}}
<table {{bind-attr class=":table showZone:hidden"}}>
<thead>
<tr>
<th>File</th>
<th width="50%">Progress</th>
</tr>
</thead>
<tbody>
{{#each file in files}}
<tr {{bind-attr class="file.errors:danger"}}>
<td>
{{file.name}}
{{#if file.errors}}
<div class="errors">
{{#each error in file.errors}}
<b>{{error.label}}</b>:
{{#each message in error.messages}} {{message}} <br> {{/each}}
{{/each}}
</div>
{{/if}}
</td>
<td class="text-align-center">
<div class="progress">
<div {{bind-attr style='file.cssStyle' class=":progress-bar file.processing:progress-bar-striped file.processing:active file.done:progress-bar-success file.errors:progress-bar-danger"}}>
{{#if file.done}}
Complete
{{/if}}
{{#if file.errors}}
Failed
{{/if}}
</div>
</div>
</td>
</tr>
{{/each}}
</tbody>
</table>
//Progress bar class for overall progress and individual file progress
var ProgressMixin = Ember.Mixin.create({
size: null, // Total size of the file
loaded: null, // Amount of the size sent to server
processing: true,
progress: function () {
return parseInt(100 * this.get('loaded') / this.get('size'), 10);
}.property('loaded', 'size'),
complete: Ember.computed.equal('progress', 100),
cssStyle: function () {
return 'width:' + this.get('progress') + '%';
}.property('progress')
});
//File class for upload
var File = Ember.Object.extend(ProgressMixin, {
name: null
});
//File Upload Component
export default Ember.Component.extend(ProgressMixin, {
classNames: ['rt-file-upload'],
// Component configuration
url: null,
// Overall upload states
done: false,
showZone: Ember.computed.equal('files.length', 0),
files: Ember.computed(function () {
return Ember.A();
}), // Each instance gets its own array
errors: null,
actions: {
addMore: function () {
this.setProperties({
done: false,
files: Ember.A(),
errors: null,
success: false,
processing: true,
loaded: 0
});
}
},
options: function () {
var self = this;
return {
dataType: 'json',
url: this.get('url'),
//individual files progress
progress: function (e, data) {
var file = self.get('files').objectAt(data.context);
file.set('loaded', data.loaded * .85); //reduce file size for server wait time
},
//all files progress
progressall: function (e, data) {
self.set('loaded', data.loaded *.85); //reduce loaded for server wait time
self.set('size', data.total);
},
// when file uploads successfully
done: function (e, data) {
var file = self.get('files').objectAt(data.context);
self.sendAction('action', data.result);
file.set('done', true);
},
// when file failes to upload
fail: function (e, data) {
var file = self.get('files').objectAt(data.context);
var errors = Ember.A();
//file was too large
if(data.jqXHR.status === 413)
{
errors.pushObject(Ember.Object.create({
label: 'Size',
messages: ['This file size exceeds the max upload size']
}));
}
else if(data.jqXHR.status === 422)// file validation errors
{
var response = $.parseJSON(data.jqXHR.responseText).errors;
for (var error in response) {
//add to files errors object
errors.pushObject(Ember.Object.create({
label: error.capitalize(),
messages: response[error]
}));
}
}
else
{
errors.pushObject(Ember.Object.create({
label: 'Error',
messages: ['There was an issue with the server. Please contact an administrator.']
}));
}
file.set('errors', errors);
self.set('errors', true);
},
// process completed for individual file
always: function(e,data)
{
var file = self.get('files').objectAt(data.context);
file.setProperties({
'processing': false,
'loaded': file.get('size')
});
},
// when all files are finished being processed
stop: function() {
self.setProperties({
'loaded': self.get('size'),
'processing': false
});
if(!self.get('errors')) self.set('done',true);
}
};
}.property(),
didInsertElement: function () {
var self = this;
Ember.assert("Please set a `url` to use the file-upload component.", this.get('url'));
this.$('input').fileupload(this.get('options')).on('fileuploadadd', function (e, data) {
data.context = self.get('files.length'); // Keep track of the file's index
var file = data.files[0];
self.get('files').pushObject(File.create({
name: file.name,
size: file.size
}));
self.set('errors', null);
});
},
willDestroyElement: function () {
this.$('input').fileupload('destroy');
}
});
<div {{bindAttr class=":zone showZone::display-none"}}>
<div class="text">
<button class="btn btn-primary">Browse Computer</button><br>
<p class="sub-text">or drag images here</p>
</div>
<input id="fileUploader" type="file" name="files[]" {{bindAttr data-url="url"}} multiple>
</div>
{{#if loading}}
<div id="allFileProgress" class="progress progress-primary">
<div id="overAllBar" class="bar"><span></span></div>
</div>
{{/if}}
{{#if completed}}
<div class="text completed">
<p class="sub-text">Upload Completed</p>
<button class="btn btn-primary" {{action addMore}}>Add More</button>
</div>
{{/if}}
<table {{bindAttr class=":table fileLength::display-none"}}>
<thead>
<tr>
<th>File</th>
<th width="50%">Progress</th>
</tr>
</thead>
<tbody id="fileRows">
</tbody>
</table>
define(function() {
return Ember.Component.extend(
{
templateName: 'fileUpload',
classNames: ['fileupload'],
//file upload states
completed : false,
loading : false,
showZone: true,
fileLength: 0,
addMore : function()
{
this.set('fileLength',0);
this.set('completed',false);
this.set('showZone',true);
this.$().find('#fileRows').empty();
},
getOptions : function()
{
var self = this;
return {
dataType: 'json',
start : function(e)
{
self.set('showZone',false);
self.set('loading',true);
},
progress: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
var id = self.get('fileLength'),
image = data.files[0].name,
file_id = 'file_'+id,
active = self.$().find('#'+file_id);
self.set('fileLength',id + 1);
if(active.length == 0)
{
var $row = $('<tr id="'+file_id+'"><td>'+image+'</td><td id="fileStatus" class="text-align-center"><div class="progress progress-primary"><div id="fileProgress" class="bar"><span></span></div></div></td></tr>');
self.$().find('#fileRows').append($row);
data.file_id = file_id;
}
else
{
$row = self.$().find('#fileRows #'+file_id);
}
var $fileProgress = $row.find('#fileProgress');
$fileProgress.css(
'width',
progress + '%'
);
if(progress == 100)
{
setTimeout(function(){
$fileProgress.find('span').text('Rendering...');
},100);
}
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
var $overAll = self.$().find('#overAllBar');
$overAll.css(
'width',
progress + '%'
);
if(progress == 100)
{
setTimeout(function(){
$overAll.find('span').text('Finishing Image Rendering...');
},100);
}
},
done: function (e, data) {
self.$().find('#'+data.file_id).find('#fileStatus').text('Finished');
},
stop : function(e)
{
self.set('completed',true);
self.set('loading',false);
//ensure all are complete since a few get stuc.. not sure why
self.$().find('#fileStatus').text('Finished');
}
};
},
didInsertElement : function()
{
this.$().find('#fileUploader').fileupload(this.getOptions());
}
});
});
@deanmraz
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment