Insert and upload are available only from a Client/Browser/Cordova/etc.
FilesCollection#insert(settings, autoStart); //[*Client*]
Upload file to a Server via DDP 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.fileId` {*String*} | Explicitly set the fileId for the file | This is an optionnal parameters `Random.id()` will be used otherwise |
`settings.fileName` {*String*} | [REQUIRED] only for `base64` uploads | For regular uploads this option is [OPTIONAL], will replace default file's name provided in HTML5 `files` item |
`settings.isBase64` {*Boolean*} | Upload as base64 string, useful for data taken from `canvas` | See Examples |
`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:
|
|
`settings.onUploaded` {*Function*} |
Callback, triggered when upload is finished Arguments:
|
|
`settings.onAbort` {*Function*} |
Callback, triggered when `abort()` method is called Arguments:
|
|
`settings.onError` {*Function*} |
Callback, triggered when upload finished with error Arguments:
|
|
`settings.onProgress` {*Function*} |
Callback, triggered after chunk is sent Arguments:
|
|
`settings.onBeforeUpload` {*Function*} |
Callback, triggered right before upload is started Arguments:
|
Use to check file-type, extension, size, etc.
|
`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` |
FilesCollection#insert()
method returns FileUpload
class instance. Note: same instance is used context in all callback functions (see above)
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*) |
`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 |
|
Name | Description | Comment |
---|---|---|
`start` |
Triggered when upload is started (*before sending first byte*) and validations was successful. Arguments:
|
|
`data` |
Triggered after each chunk is read. Arguments:
|
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:
|
|
`pause` |
Triggered after upload process set to pause. Arguments:
|
|
`continue` |
Triggered after upload process is continued from pause. Arguments:
|
|
`abort` |
Triggered after upload is aborted. Arguments:
|
|
`uploaded` |
Triggered when upload is finished. Arguments:
|
|
`error` |
Triggered whenever upload has an error. Arguments:
|
|
`end` |
Triggered at the very end of upload or by `.abort()`. In case if `end` triggered by `.abort()`, the server could return a `408` response code. Arguments:
|
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 bytestype
{String}mime
,mime-type
{String}ext
,extension
{String}name
{String} - File name
Upload form and .insert()
method examples
Shared code:
// /imports/collections/images.js
import { FilesCollection } from 'meteor/ostrio:files';
const imagesCollection = new FilesCollection({collectionName: 'images'});
// Export created instance of the FilesCollection
export { imagesCollection };
Client's code:
import { ReactiveVar } from 'meteor/reactive-var';
import { Template } from 'meteor/templating';
import { imagesCollection } from '/imports/collections/images.js';
Template.uploadForm.onCreated(function () {
this.currentFile = new ReactiveVar(false);
});
Template.uploadForm.helpers({
currentFile() {
Template.instance().currentFile.get();
}
});
Template.uploadForm.events({
'change #fileInput'(e, template) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// there was multiple files selected
const file = e.currentTarget.files[0];
imagesCollection.insert({
file: file,
onStart() {
template.currentFile.set(this);
},
onUploaded(error, fileObj) {
if (error) {
alert('Error during upload: ' + error);
} else {
alert(`File "${fileObj.name}" successfully uploaded`);
}
template.currentFile.set(false);
},
chunkSize: 'dynamic'
});
}
}
});
Events-driven upload
import { Template } from 'meteor/templating';
import { imagesCollection } from '/imports/collections/images.js';
Template.uploadForm.events({
'change #fileInput'(e, template) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// multiple files were selected
imagesCollection.insert({
file: e.currentTarget.files[0],
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();
}
}
});
Another way to upload using events:
import { Template } from 'meteor/templating';
import { imagesCollection } from '/imports/collections/images.js';
Template.uploadForm.events({
'change #fileInput'(e, template) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
const uploader = imagesCollection.insert({
file: e.currentTarget.files[0],
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();
}
}
});
import { imagesCollection } from '/imports/collections/images.js';
// As dataURI
imagesCollection.insert({
file: 'data:image/png,base64str…',
isBase64: true, // <— Mandatory
fileName: 'pic.png' // <— Mandatory
});
// As base64:
imagesCollection.insert({
file: 'image/png,base64str…',
isBase64: true, // <— Mandatory
fileName: 'pic.png' // <— Mandatory
});
// As plain base64:
imagesCollection.insert({
file: 'base64str…',
isBase64: true, // <— Mandatory
fileName: 'pic.png', // <— Mandatory
type: 'image/png' // <— Mandatory
});
Note: data flow in ddp
and http
uses dataURI (e.g. Base64)
import { Template } from 'meteor/templating';
import { imagesCollection } from '/imports/collections/images.js';
const encrypt = function encrypt(data) {
return someHowEncryptAndReturnAsBase64(data);
};
const zip = function zip(data) {
return someHowZipAndReturnAsBase64(data);
};
Template.uploadForm.events({
'change #fileInput'(e) {
if (e.currentTarget.files && e.currentTarget.files[0]) {
// We upload only one file, in case
// multiple files were selected
imagesCollection.insert({
file: e.currentTarget.files[0],
chunkSize: 'dynamic'
}, false).pipe(encrypt).pipe(zip).start();
}
}
});