I'm running a website, where I'd like to upload files with Drag 'n Drop, using the HTML5 File API and FileReader. I have successfully managed to create a new FileReader, but I don't know how to upload the file. My code (JavaScript) is the following:
holder = document.getElementById('uploader');
holder.ondragover = function () {
$("#uploader").addClass('dragover');
return false;
};
holder.ondragend = function () {
$("#uploader").removeClass('dragover');
return false;
};
holder.ondrop = function (e) {
$("#uploader").removeClass('dragover');
e.preventDefault();
var file = e.dataTransfer.files[0],
reader = new FileReader();
reader.onload = function (event) {
//I shoud upload the file now...
};
reader.readAsDataURL(file);
return false;
};
I also have a form (id : upload-form) and an input file field (id : upload-input).
Do you have any ideas?
P.S. I use jQuery, that's why there is $("#uploader") and others.
Rather than code this from scratch, why not use something like html5uploader, which works via drag n drop (uses FileReader etc.): http://code.google.com/p/html5uploader/
EDIT: apparently we respondents are supposed to tend to our answers forever more, for fear for down-votes. The Google Code link is now dead (four years later), so here's a jQuery plugin that is very similar: http://www.igloolab.com/jquery-html5-uploader/
You'll want to extract the base64 encoded file contents and ajax them over tot the server.
JavaScript
var extractBase64Data;
extractBase64Data = function(dataUrl) {
return dataUrl.substring(dataUrl.indexOf(',') + 1);
};
// Inside the ondrop event
Array.prototype.forEach.call(event.dataTransfer.files, function(file) {
var reader;
if (!file.type.match(options.matchType)) {
return;
}
reader = new FileReader();
reader.onload = function(event) {
var contentsBase64;
if (event.target.readyState === FileReader.DONE) {
contentsBase64 = extractBase64Data(event.target.result);
return $.post(someURL, {
contentsBase64: contentsBase64
});
}
};
reader.readAsDataURL(file);
});
CoffeeScript
extractBase64Data = (dataUrl) ->
dataUrl.substring(dataUrl.indexOf(',') + 1)
# Inside the ondrop event
Array::forEach.call event.dataTransfer.files, (file) ->
return unless file.type.match(options.matchType)
reader = new FileReader()
reader.onload = (event) ->
if event.target.readyState == FileReader.DONE
contentsBase64 = extractBase64Data(event.target.result)
$.post someURL,
contentsBase64: contentsBase64
reader.readAsDataURL(file)
Related
I'm tyring to upload a static json file into an indexedDB ONLY when an upgrade is needed (i.e. onupgradeneeded). I've search for answers to this repeatedly but have yet to see code examples of how to approach this.
My current code below gets the json file every time the page opens, which is of course inefficient since I only need to get the json file if the indexedDB has not yet been created or needs upgraded.
I tried putting the xhr.onload section into the end of the .onupgradeneeded function, but as many have noted, the .onsuccess gets called before the xhr.onload has completed.
var jsonUrl = '/path/to/hcLookup.json');
var req, db, hcObjectStore, objectStore, data, dataArr, trans, addreq, key;
var xhr = new XMLHttpRequest();
xhr.open("GET", jsonUrl, true);
xhr.type='json';
xhr.send();
xhr.onload = function(msg) {
data = msg.target.response;
req = window.indexedDB.open("hcLookup", 1);
req.onerror=function(event){console.log("onerror: " + event.target.errorCode)};
req.onsuccess = function(event){
console.log("ready.");
};
req.onupgradeneeded = function(event){
db = event.target.result;
objectStore = db.createObjectStore("hcLookup", {autoIncrement: true});
objectStore.createIndex("S", "S", {unique: false});
// make sure the objectStore creation is finished before adding data into it
objectStore.transaction.oncomplete = function (event) {
// Store values in the newly created objectStore.
trans = db.transaction(["hcLookup"], "readwrite");
hcObjectStore = trans.objectStore("hcLookup");
// Do something when all the data is added to the database.
trans.oncomplete = function (event) {
console.log("upgrading done!");
};
trans.onerror = function (event) {
console.log("bulk add onerror: " + event.target.errorCode)
};
//convert JSON to an strArray in order to add the dataArr into to the objectStore
dataArr = JSON.parse(data);
for (var i in dataArr) {
addreq = hcObjectStore.add(dataArr[i]);
}
};
};
};
There's an example from MDN on how to use FileReader to show a preview image:
function handleFiles(files) {
for (var i = 0; i < files.length; i++) {
var file = files[i];
var imageType = /^image\//;
if (!imageType.test(file.type)) {
continue;
}
var img = document.createElement("img");
img.classList.add("obj");
img.file = file;
preview.appendChild(img); // Assuming that "preview" is the div output where the content will be displayed.
var reader = new FileReader();
reader.onload = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img);
reader.readAsDataURL(file);
}
}
I'm wondering how to use this in a Vue component. It seems to me the asynchronous part isn't that easy to handle, but I'm new to Vue, and maybe that's an advanced feature.
Create a component with an <img :src="src" id="img> tag and src property in it's data object. You could pass an idx prop from parent component along with a file if you would like to make a gallery and and it to an img id, because as we reference an image by id we need unique id for each img element.
Create a method loadPicture
loadPicture(file) {
let self = this;
let img = document.getElementById('img');
var reader = new FileReader();
reader.onload = function(e) {
self.src = e.target.result;
}
reader.readAsDataURL(file);
}`
Then call this method in mounted lifecycle
mounted() {
this.loadPicture();
}
Working example: https://jsfiddle.net/8dnhh23o/
Multiple images example: https://jsfiddle.net/o1037uks/
I have an audio file/blob that has been created using the MediaRecorder api:
let recorder = new MediaRecorder(this.stream)
let data = [];
recorder.ondataavailable = event => data.push(event.data);
and then later when the recording is finished:
let superBlob = new Blob(data, { type: "video/webm" });
How can I use this blob to create an AudioBuffer? I need to either :
Transform the Blob object into an ArrayBuffer which I could use with AudioContext.decodeAudioData (returns an AudioBuffer) or
Transform the Blob object into an Float32Array, where I could copy it into the AudioBuffer with AudioBuffer.copyToChannel()
Any tips on how to achieve that are appreciated. Cheers!
To convert a Blob object to an ArrayBuffer, use FileReader.readAsArrayBuffer.
let fileReader = new FileReader();
let arrayBuffer;
fileReader.onloadend = () => {
arrayBuffer = fileReader.result;
}
fileReader.readAsArrayBuffer(superBlob);
The accepted answer is great but only gives an array buffer which is not an audio buffer. You need to use the audio context to convert the array buffer into an audio buffer.
const audioContext = AudioContext()
const fileReader = new FileReader()
// Set up file reader on loaded end event
fileReader.onloadend = () => {
const arrayBuffer = fileReader.result as ArrayBuffer
// Convert array buffer into audio buffer
audioContext.decodeAudioData(arrayBuffer, (audioBuffer) => {
// Do something with audioBuffer
console.log(audioBuffer)
})
}
//Load blob
fileReader.readAsArrayBuffer(blob)
I wish the answer had included an example using decodeAudioData. I had to find it somewhere else and I thought since this is the top search for "Blob to Audio Buffer" I would add some helpful information for the next person that comes down this rabbit hole.
All the answers are true. However, in the modern web browsers like Chrome 76 and Firefox 69, there is a much simpler way: using Blob.arrayBuffer()
Since Blob.arrayBuffer() returns a Promise, you can do either
superBlob.arrayBuffer().then(arrayBuffer => {
// Do something with arrayBuffer
});
or
async function doSomethingWithAudioBuffer(blob) {
var arrayBuffer = await blob.arrayBuffer();
// Do something with arrayBuffer;
}
A simplified version using an async function:
async function blobToAudioBuffer(audioContext, blob) {
const arrayBuffer = await blob.arrayBuffer();
return await audioContext.decodeAudioData(arrayBuffer);
}
I put audioContext as a param, because I recommend reusing instances.
Both Answers are true, there are some minor changes. This is the function I finally used:
function convertBlobToAudioBuffer(myBlob) {
const audioContext = new AudioContext();
const fileReader = new FileReader();
fileReader.onloadend = () => {
let myArrayBuffer = fileReader.result;
audioContext.decodeAudioData(myArrayBuffer, (audioBuffer) => {
// Do something with audioBuffer
});
};
//Load blob
fileReader.readAsArrayBuffer(myBlob);
}
I am using mongoskin to connect mongodb in my project. Now I have requirement to use GridFs to upload images, audio etc. I have one HTML form to upload these files.
I tried to find out example code to upload file using mongoskin however could't find any good one.
Please help.
After spending many hours; I am able to use mongoskin to upload file to Gridfs. Not sure if this is perfect code however sharing it here because I couldn't find any single working code on searching Google :-)
https://github.com/dilipkumar2k6/gridfs-mongoskin
var DBModule = require('./DBModule.js');
var Grid = require('gridfs-stream');
var mongoskin = require('mongoskin');
//Upload file to server and also update the database
exports.uploadContent = function (req, res) {
console.log('Calling uploadFile inside FileUploadService');
req.pipe(req.busboy);
req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
console.log('uploadFile after busboy fieldname: ' + fieldname + ", file : " + file + ", filename : " + filename);
// make sure the db instance is open before passing into `Grid`
var gfs = Grid(DBModule.db, mongoskin);
//Get metadata var host = req.headers['host'];
var metadata = {contentType: mimetype};
var writestream = gfs.createWriteStream({filename: filename, metadata: metadata});
file.pipe(writestream);
writestream.on('close', function (file) {
// return URL to acces the uploaded content
var path = "contents/" + file._id;
res.json({"path": path});
});
writestream.on('error', function (err) {
log.error({err: err}, 'Failed to upload file to database');
res.status(constants.HTTP_CODE_INTERNAL_SERVER_ERROR);
res.json({error: err});
});
});
};
//view file from database
exports.previewContent = function (req, res) {
var contentId = new DBModule.BSON.ObjectID(req.params.contentid);
console.log('Calling previewFile inside FileUploadService for content id ' + contentId);
var gs = DBModule.db.gridStore(contentId, 'r');
gs.read(function (err, data) {
if (!err) {
//res.setHeader('Content-Type', metadata.contentType);
res.end(data);
} else {
log.error({err: err}, 'Failed to read the content for id ' + contentId);
res.status(constants.HTTP_CODE_INTERNAL_SERVER_ERROR);
res.json({error: err});
}
});
};
Try this to store the data using gridfs (by default uses mongoskin). It worked for me.
var ObjectID = require('mongodb').ObjectID,
GridStore = require('mongodb').GridStore;
exports.saveMedia = function(db, media, next) {
console.log(media)
db.open(function (err, db) {
// Create a file and open it
var gridStore = new GridStore(db, new ObjectID(), "w");
gridStore.open(function (err, gridStore) {
// Write some content to the file
gridStore.write(new Buffer(media), function (err, gridStore) {
// Flush the file to db
gridStore.close(function (err, fileData)
//returns filename
next(null, fileData)
});
});
});
});
}
I'm able to create the JSZip object in my code, but I'm having trouble saving that to local storage in my windows 8 app. The examples I'm able to find set the browser's location.href to trigger a download, which isn't really an option for me.
I've included my code below. The zip file I end up with is invalid and can't be opened. Any help would be appreciated.
For reference: JSZip
function _zipTest() {
var dbFile = null;
var zipData = null;
Windows.Storage.StorageFile.getFileFromPathAsync(config.db.path)
.then(function (file) {
dbFile = file;
return Windows.Storage.FileIO.readBufferAsync(file);
})
.then(function (buffer) {
//Read the database file into a byte array and create a new zip file
zipData = new Uint8Array(buffer.length);
var dataReader = Windows.Storage.Streams.DataReader.fromBuffer(buffer);
dataReader.readBytes(zipData);
dataReader.close();
var localFolder = Windows.Storage.ApplicationData.current.localFolder;
return localFolder.createFileAsync(dbFile.displayName.concat('.zip'), Windows.Storage.CreationCollisionOption.replaceExisting)
})
.then(function (file) {
//Write the zip data to the new zip file
var zip = new JSZip();
zip.file(dbFile.displayName, zipData);
var content = zip.generate();
return Windows.Storage.FileIO.writeTextAsync(file, content);
});
}
you can do something on these lines. This code seem to generate valid .zip file in the temp folder.
var zip = new JSZip();
var storage = Windows.Storage;
storage.StorageFile.getFileFromApplicationUriAsync(new Windows.Foundation.Uri('ms-appx:///images/logo.png')).then(function ongetfile(file)
{
var blob = MSApp.createFileFromStorageFile(file);
var url = URL.createObjectURL(blob, { oneTimeOnly: true });
return WinJS.xhr({ url: url, responseType: 'arraybuffer' });
}).then(function onreadbuffer(req)
{
var b = req.response;
zip.file('logo.png', b);
return storage.ApplicationData.current.temporaryFolder.createFileAsync('a.zip', storage.CreationCollisionOption.replaceExisting);
}).then(function onnewfile(out)
{
var content = zip.generate({ type: 'uint8array' });
return storage.FileIO.writeBytesAsync(out, content);
}).then(null, function onerror(error)
{
// TODO: error handling
});