I have a Meteor app and I am interested in getting image upload to work in the simplest possible manner.
The simplest manner I can come up with is to somehow convert the image to a base64 string on the client and the save it to the database as a string.
How is it possible to convert an image on the users filesystem to a base64 string and then save it to the database?
You can use an HTML5 file input :
HTML
<template name="fileUpload">
<form>
<input type="file" name="imageFile">
<button type="submit" disabled={{submitDisabled}}>
Submit
</button>
</form>
</template>
Then listen to the change event and use a FileReader
to read the local file as a base64 data url that we're going to store in a reactive var :
Template.fileUpload.created=function(){
this.dataUrl=new ReactiveVar();
};
Template.fileUpload.events({
"change input[type='file']":function(event,template){
var files=event.target.files;
if(files.length===0){
return;
}
var file=files[0];
//
var fileReader=new FileReader();
fileReader.onload=function(event){
var dataUrl=event.target.result;
template.dataUrl.set(dataUrl);
});
fileReader.readAsDataURL(file);
}
});
Then we can use the reactive var value to allow/disallow form submission and send the value to the server :
Template.fileUpload.helpers({
submitDisabled:function(){
return Template.instance().dataUrl.get();
}
});
Template.fileUpload.events({
"submit":function(event,template){
event.preventDefault();
//
Meteor.call("uploadImage",template.dataUrl.get());
}
});
You will need to define a server method that saves the dataUrl
to some collection field value, what's cool about dataUrl
s is that you can use them directly as an image tag src
.
Note that this solution is highly unscalable as the image data won't be cachable and will pollute the app database regular communications (which should only contain text-like values).
You could fetch the base64 data from the dataUrl
and upload it to Google Cloud Storage or Amazon S3 and serve the files behind a CDN.
You could also use services that do all of this stuff for you like uploadcare or filepicker.
EDIT :
This solution is easy to implement but comes with the main drawback that fetching large base64 strings from mongodb will slow your app from fetching other data, DDP communications are always live and not cachable at the moment so your app will always redownload image data from the server.
You wouldn't save dataUrl
s to Amazon, you would save the image directly, and it would be fetched by your app using an Amazon URL with a cachable HTTP request.
You have two choices when it comes to file upload : you can upload them directly from the client using specific javascript browser APIs or you can upload them within Node.js (NPM modules) APIs in the server.
In the case you want to upload from the server (which is usually simpler because you don't need to require that the users of your apps authenticate against third party services, only your server will act as a trusted client to communicate with Amazon API), then you can send the data that a user want to upload through a method call with a dataUrl
as argument.
If you don't want to dive into all this stuff consider using uploadcare or filepicker, but keep in mind that these are paid services (as is Amazon S3 BTW).
Not sure if this is the best way, but you can easily do this with a file reader. In the Template event handler where you get the file contents, you can pass the file to the reader and get back a base64 string. For example, something like this:
Template.example.events({
'submit form': function (event, template) {
var reader = new FileReader();
var file = template.find('#fileUpload').files[0]; // get the file
reader.onload = function (event) {
// event.target.result is the base64 string
}
reader.readAsDataURL(file);
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With