Skip to content

Insert (Upload)

dr.dimitru edited this page Oct 12, 2016 · 33 revisions
insert(settings[, autoStart]) [Client]

Upload file to Server via DDP, RTC/DC or HTTP.

Param/Type Description Comment
settings {Object} [REQUIRED] See all options below
settings.file {File} or {Object} or {String} [REQUIRED] HTML5 files item Ex.: From event: event.currentTarget.files[0]
Set to dataURI {String} for Base64
settings.isBase64 {Boolean} Upload as base64 string, useful for data taken from canvas [See Examples](https://github.com/VeliovGroup/Meteor-Files/wiki/Insert-(Upload)#upload-base64-string)
settings.meta {Object} Additional file-related data Ex.: ownerId, postId, etc.
settings.transport {String} Must be set to http or ddp Note: upload via http is at least twice faster. HTTP will properly work only with "sticky sessions"
Default: ddp
settings.ddp {Object} Custom DDP connection for upload. Object returned form DDP.connect() By default Meteor (The default DDP connection)
settings.onStart {Function} Callback, triggered when upload is started and validations was successful
Arguments:
  • error - Always null
  • fileData {Object}
settings.onUploaded {Function} Callback, triggered when upload is finished
Arguments:
  • error
  • fileRef {Object} - File record from DB
settings.onAbort {Function} Callback, triggered when abort() method is called
Arguments:
  • fileData {Object}
settings.onError {Function} Callback, triggered when upload finished with error
Arguments:
  • error
  • fileData {Object}
settings.onProgress {Function} Callback, triggered after chunk is sent
Arguments:
  • progress {Number} - Current progress from 0 to 100
  • fileData {Object}
settings.onBeforeUpload {Function} Callback, triggered right before upload is started
Arguments:
  • fileData {Object}
Use to check file-type, extension, size, etc.
  • return true to continue
  • return false to abort or {String} to abort upload with message
settings.streams {Number|dynamic} Quantity of parallel upload streams dynamic is recommended
settings.chunkSize {Number|dynamic} Chunk size for upload dynamic is recommended
settings.allowWebWorkers {Boolean} Use WebWorkers (To avoid main thread blocking) whenever feature is available in browser Default: true
autoStart {Boolean} Start upload immediately If set to false, you need manually call .start() method on returned class. Useful to set EventListeners, before starting upload. Default: true

insert() method returns FileUpload class instance. Note: same instance is used as context in all callback functions (see above)

FileUpload methods and properties:

Name/Type Description Comment
file {File} Source file passed into insert() method
onPause {ReactiveVar} Is upload process on the pause?
progress {ReactiveVar} Upload progress in percents 0 - 100
pause() {Function} Pause upload process
continue() {Function} Continue paused upload process
toggle() {Function} Toggle continue/pause if upload in the progress
abort() {Function} Abort current upload, then trigger onAbort callback
pipe() {Function} Pipe data before upload All data must be in data URI scheme (*Base64*)
Only for webrtc transport data represented as ArrayBuffer.
estimateTime {ReactiveVar} Remaining upload time in milliseconds
estimateSpeed {ReactiveVar} Current upload speed in bytes/second To convert into speed, take a look on filesize package, usage: filesize(estimateSpeed, {bits: true}) + '/s';
state {ReactiveVar} String, indicates current state of the upload
  • active - file is currently actively uploading
  • paused - file upload is paused
  • aborted - file upload has been aborted and can no longer be completed
  • completed - file has been successfully uploaded

Events map:

Name Description Comment
start Triggered when upload is started (before sending first byte) and validations was successful.
Arguments:
  • error - Always null
  • fileData {Object}
data Triggered after each chunk is read.
Arguments:
  • data {String} - Base64 encoded chunk (DataURL)
Can be used to display previews or do something else with loaded file during upload. To get EOF use readEnd event
readEnd Triggered after file is fully read by browser Has no arguments
progress Triggered after each chunk is sent.
Arguments:
  • progress {Number} - Current progress from 0 to 100
  • fileData {Object}
pause Triggered after upload process set to pause.
Arguments:
  • fileData {Object}
continue Triggered after upload process is continued from pause.
Arguments:
  • fileData {Object}
abort Triggered after upload is aborted.
Arguments:
  • fileData {Object}
uploaded Triggered when upload is finished.
Arguments:
  • error
  • fileRef {Object} - File record from DB
error Triggered whenever upload has an error.
Arguments:
  • error
  • fileData {Object}
end Triggered at the very end of upload.
Arguments:
  • error
  • fileRef {Object} - File record from DB

When autoStart is false before calling .start() you can "pipe" data through any function, data comes as Base64 string (DataURL). You must return Base64 string from piping function, for more info - see example below. Do not forget to change file name, extension and mime-type if required.

The fileData object (see above):

  • size {Number} - File size in bytes
  • type {String}
  • mime, mime-type {String}
  • ext, extension {String}
  • name {String} - File name

Upload form:

<template name="uploadForm">
  {{#if currentFile}}
    {{#with currentFile}
      <span id="progress">{{progress}}%</span>
    {{/with}}
  {{else}}
    <input id="fileInput" type="file" />
  {{/if}}
</template>

Shared code:

this.Images = new FilesCollection({collectionName: 'Images'});

Client's code:

Template.uploadForm.onCreated(function () {
  this.currentFile = new ReactiveVar(false);
});

Template.uploadForm.helpers({
  currentFile: function () {
    Template.instance().currentFile.get();
  }
});

Template.uploadForm.events({
  'change #fileInput': function (e, template) {
    if (e.currentTarget.files && e.currentTarget.files[0]) {
      // We upload only one file, in case
      // there was multiple files selected
      var file = e.currentTarget.files[0];

      Images.insert({
        file: file,
        onStart: function () {
          template.currentFile.set(this);
        },
        onUploaded: function (error, fileObj) {
          if (error) {
            alert('Error during upload: ' + error);
          } else {
            alert('File "' + fileObj.name + '" successfully uploaded');
          }
          template.currentFile.set(false);
        },
        streams: 'dynamic',
        chunkSize: 'dynamic'
      });
    }
  }
});
Alternative, using events:
Template.uploadForm.events({
  'change #fileInput': function (e, template) {
    if (e.currentTarget.files && e.currentTarget.files[0]) {
      // We upload only one file, in case
      // multiple files were selected
      Images.insert({
        file: e.currentTarget.files[0],
        streams: 'dynamic',
        chunkSize: 'dynamic'

      }, false).on('start', function () {
        template.currentFile.set(this);

      }).on('end', function (error, fileObj) {
        if (error) {
          alert('Error during upload: ' + error);
        } else {
          alert('File "' + fileObj.name + '" successfully uploaded');
        }
        template.currentFile.set(false);

      }).start();
    }
  }
});
Events based example:
Template.uploadForm.events({
  'change #fileInput': function (e, template) {
    if (e.currentTarget.files && e.currentTarget.files[0]) {
      var uploader = Images.insert({
        file: e.currentTarget.files[0],
        streams: 'dynamic',
        chunkSize: 'dynamic'
      }, false);

      uploader.on('start', function () {
        template.currentFile.set(this);
      });

      uploader.on('end', function (error, fileObj) {
        template.currentFile.set(false);
      });

      uploader.on('uploaded', function (error, fileObj) {
        if (!error) {
          alert('File "' + fileObj.name + '" successfully uploaded');
        }
      });

      uploader.on('error', function (error, fileObj) {
        alert('Error during upload: ' + error);
      });

      uploader.start();
    }
  }
});
Upload base64 string:
// As dataURI
Images.insert({
  file: 'data:image/png,base64str…',
  isBase64: true, // <— Mandatory
  fileName: 'pic.png' // <— Mandatory
});

// As base64:
Images.insert({
  file: 'image/png,base64str…',
  isBase64: true, // <— Mandatory
  fileName: 'pic.png' // <— Mandatory
});

// As plain base64:
Images.insert({
  file: 'base64str…',
  isBase64: true, // <— Mandatory
  fileName: 'pic.png', // <— Mandatory
  type: 'image/png' // <— Mandatory
});
Piping:

Note: data flow in webrtc transport uses ArrayBuffer, while ddp and http uses dataURI (Base64). webrtc is available only on webrtc-data-channel branch.

var encrypt = function encrypt(data) {
  return someHowEncryptAndReturnAsBase64(data);
};

var zip = function zip(data) {
  return someHowZipAndReturnAsBase64(data);
};

Template.uploadForm.events({
  'change #fileInput': function (e, template) {
    if (e.currentTarget.files && e.currentTarget.files[0]) {
      // We upload only one file, in case
      // multiple files were selected
      Images.insert({
        file: e.currentTarget.files[0],
        streams: 'dynamic',
        chunkSize: 'dynamic'
      }, false).pipe(encrypt).pipe(zip).start();
    }
  }
});
Clone this wiki locally