This is the code I have for reading the first item in a file input, how can I iterate over all items inside this input?
function readFile (uploadControlId) {
if (!window.FileReader)
throw "The browser does not support HTML 5";
var element = document.getElementById(uploadControlId);
var def = new $.Deferred();
var file = element.files[0];
var parts = element.value.split("\\");
var fileName = parts[parts.length - 1];
var reader = new FileReader();
reader.onload = function (e) {
if (uploadControlId == 'uploadControlId'){
def.resolve(e.target.result, fileName);
} else {
def.resolve(e.target.result, fileName);
}
};
reader.onerror = function (e) {
def.reject(e.target.error);
};
reader.readAsArrayBuffer(file);
return def.promise();
}
I have tried something like:
angular.forEach(element.files, function (file){
})
But this doesn't work since the variables 'parts' and 'fileName' is from the variable 'element', so if I iterate over each file in element, they get 'undefined' fileName, this means they won't have like .txt or .pdf, so they are unreadable.
Update: This give no error, but only the last file gets uploaded:
function readFile (uploadControlId) {
if (!window.FileReader)
throw "The browser does not support HTML 5";
var def = new $.Deferred();
var element = document.getElementById(uploadControlId);
angular.forEach(element.files, function(file){
var fileName = file.name;
var reader = new FileReader();
reader.onload = function (e) {
def.resolve(e.target.result, fileName);
};
reader.onerror = function (e) {
def.reject(e.target.error);
};
reader.readAsArrayBuffer(file);
});
return def.promise();
}
My upload function:
$scope.UploadAttachment = function(){
readFile(uploadControlId).done(function (buffer, fileName) {
// logic to upload to server
}).fail(function (err) {
alert("error in reading file content");
});
};
Have you added the "multiple" attribute on the input tag?
By the way if you add this directive to your tag, an event will be fired with all files and you will handle that in you controller.
// Directive
(function(){
var Directive = function(){
return {
restrict: 'A',
scope : {},
link : function(scope, element, attrs){
element.bind('change', function(changeEvent){
scope.$emit('fileReader', changeEvent.target.files);
});
}
}
};
Directive.$inject = [];
app.directive('fileReader', Directive);
})();
// Controller
(function(){
var Controller = function($scope){
// Methods
function fileReader(files){
for(var iFile = 0, fileLen = files.length; iFile < fileLen; iFile = iFile + 1){
var file = files[iFile];
// Do something
}
}
// Events
$scope.$on('fileReader', function(event, files){
fileReader(files);
});
};
Controller.$inject = [
'$scope'
];
app.controller('MainCtrl', Controller);
})();
Related
These are the functions which load file and write file. I used JavaScript and XPCOM for these operations. You can use these functions in iMacros JavaScript file.
Edit: These functions work best in iMacros version 8.9.7 and corresponding Firefox. The later versions of iMacros addon don't support JavaScript. Also it's best to use Firefox 47 with disabled updates. And you can use latest Pale Moon browser with addon 8.9.7 . If there is a content in file the WriteFile function simply adds data in new line.
//This function load content of the file from a location
//Example: LoadFile("C:\\test\\test.txt")
function LoadFile(path) {
try {
Components.utils.import("resource://gre/modules/FileUtils.jsm");
var file = new FileUtils.File(path);
file.initWithPath(path);
var charset = 'UTF8';
var fileStream = Components.classes['#mozilla.org/network/file-input-stream;1']
.createInstance(Components.interfaces.nsIFileInputStream);
fileStream.init(file, 1, 0, false);
var converterStream = Components.classes['#mozilla.org/intl/converter-input-stream;1']
.createInstance(Components.interfaces.nsIConverterInputStream);
converterStream.init(fileStream, charset, fileStream.available(),
converterStream.DEFAULT_REPLACEMENT_CHARACTER);
var out = {};
converterStream.readString(fileStream.available(), out);
var fileContents = out.value;
converterStream.close();
fileStream.close();
return fileContents;
} catch (e) {
alert("Error " + e + "\nPath" + path)
}
}
//This function writes string into a file
function WriteFile(path, string) {
try {
//import FileUtils.jsm
Components.utils.import("resource://gre/modules/FileUtils.jsm");
//declare file
var file = new FileUtils.File(path);
//declare file path
file.initWithPath(path);
//if it exists move on if not create it
if (!file.exists()) {
file.create(file.NORMAL_FILE_TYPE, 0666);
}
var charset = 'UTF8';
var fileStream = Components.classes['#mozilla.org/network/file-output-stream;1']
.createInstance(Components.interfaces.nsIFileOutputStream);
fileStream.init(file, 18, 0x200, false);
var converterStream = Components
.classes['#mozilla.org/intl/converter-output-stream;1']
.createInstance(Components.interfaces.nsIConverterOutputStream);
converterStream.init(fileStream, charset, string.length,
Components.interfaces.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
//write file to location
converterStream.writeString(string + "\r\n");
converterStream.close();
fileStream.close();
} catch (e) {
alert("Error " + e + "\nPath" + path)
}
}
//this function removes file from location
function RemoveFile(path) {
var file = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//file.initWithPath("c:\\batstarter6_ff.cmd");
file.initWithPath(path);
/*
var file = IO.newFile(path, name);
*/
file.remove(false);
}
// Download a file form a url.
function saveFile(url) {
try {
// Get file name from url.
var filename = url.substring(url.lastIndexOf("/") + 1).split("?")[0];
var xhr = new XMLHttpRequest();
xhr.responseType = 'blob';
xhr.onload = function () {
var a = document.createElement('a');
a.href = window.URL.createObjectURL(xhr.response); // xhr.response is a blob
a.download = filename; // Set the file name.
a.style.display = 'none';
document.body.appendChild(a);
a.click();
delete a;
};
xhr.open('GET', url);
xhr.send();
} catch (e) {
alert("Error " + e)
}
}
/*
This function runs file from given path
*/
function RunFile(path) {
var file = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//file.initWithPath("c:\\batstarter6_ff.cmd");
file.initWithPath(path);
file.launch();
}
//this function downloads a file from url
function downloadFile(httpLoc, path) {
try {
//new obj_URI object
var obj_URI = Components.classes["#mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(httpLoc, null, null);
//new file object
var obj_TargetFile = Components.classes["#mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//set file with path
obj_TargetFile.initWithPath(path);
//if file doesn't exist, create
if (!obj_TargetFile.exists()) {
obj_TargetFile.create(0x00, 0644);
}
//new persitence object
var obj_Persist = Components.classes["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);
// with persist flags if desired
const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
const flags = nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
obj_Persist.persistFlags = flags | nsIWBP.PERSIST_FLAGS_FROM_CACHE;
/*
var privacyContext = sourceWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsILoadContext);*/
//save file to target
obj_Persist.saveURI(obj_URI, null, null, null, null, obj_TargetFile, null);
} catch (e) {
alert(e);
}
}
//This function prompts user to select file from folder and use it
function PickFile(title) {
const nsIFilePicker = Components.interfaces.nsIFilePicker;
var fp = Components.classes["#mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
fp.init(window, title, nsIFilePicker.modeOpen);
fp.appendFilters(nsIFilePicker.filterAll | nsIFilePicker.filterText);
var rv = fp.show();
if (rv == nsIFilePicker.returnOK || rv == nsIFilePicker.returnReplace) {
var file = fp.file;
// Get the path as string. Note that you usually won't
// need to work with the string paths.
var path = fp.file.path;
// work with returned nsILocalFile...
return path;
}
}
//This function prompts user to select folder from folder and use it
function PickFolder(title) {
var picker = Components.classes["#mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
picker.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
//folder
picker.init(window, title, Components.interfaces.nsIFilePicker.modeGetFolder);
//or file
// picker.init (window, "Choice file", Components.interfaces.nsIFilePicker.modeOpen);
if (picker.show() == Components.interfaces.nsIFilePicker.returnOK) {
return picker.file.path;
} else {
return false;
}
}
//this function offers a set of options to select from
//items is an array of options
//title is the dialog title
//qustion is a question asked to user.
function Select(items, title, question) {
var prompts = Components.classes["#mozilla.org/embedcomp/prompt-service;1"]
.getService(Components.interfaces.nsIPromptService);
//var items = ["Articles", "Modules", "Both"]; // list items
var selected = {};
var result = prompts.select(null, title, question, items.length,
items, selected);
// result is true if OK was pressed, false if cancel. selected is the index of the item array
// that was selected. Get the item using items[selected.value].
var selected = items[selected.value];
return selected;
}
Edit: I am also adding iMacros version 8.9.7 addon to download because version 10 doesn't support JavaScript http://download.imacros.net/imacros_for_firefox-8.9.7-fx.xpi
Edit1: I added some more useful functions for iMacros.
I am trying to post javascript array of object in an ajax call but i get string value "[]". When i try to console.log the array lenght it says zero.
Following is the code i am using
var masterFileArray = []; // where I will store the contents
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (files) {
for (var i = 0, f; f = files[i]; i++) {
var r = new FileReader();
r.onload = (function (f) {
return function (e) {
var contents = e.target.result;
masterFileArray.push({name:f.name, contents: contents, type:f.type, size:f.size}); // storing as object
};
})(f);
r.readAsText(f);
}
console.log(masterFileArray);
new Ajax.Request('fileupload.php', {
method: 'post',
parameters: {files: JSON.stringify(masterFileArray)},
onSuccess: function(transport){
var response = transport.responseText;
console.log(response);
}
});
} else {
alert('Failed to load files');
}
}
document.getElementById('upfiles').addEventListener('change', readMultipleFiles, false);
Thats how it looks like on inspection
What i am doing wrong? Any help would be appreciated, Thank you.
You can post after reading finished,
Here introduced left_loaded_count to get the status of reading.
Try like this.
var masterFileArray = []; // where I will store the contents
var left_loaded_count = 0;
function readMultipleFiles(evt) {
//Retrieve all the files from the FileList object
var files = evt.target.files;
if (files) {
for (var i = 0, f; f = files[i]; i++) {
var r = new FileReader();
r.onload = (function (f) {
return function (e) {
var contents = e.target.result;
masterFileArray.push({name:f.name, contents: contents, type:f.type, size:f.size}); // storing as object
left_loaded_count -= 1;
if(left_loaded_count == 0)
{
console.log(masterFileArray);
new Ajax.Request('fileupload.php', {
method: 'post',
parameters: {files: JSON.stringify(masterFileArray)},
onSuccess: function(transport){
var response = transport.responseText;
console.log(response);
}
});
}
};
})(f);
left_loaded_count += 1;
r.readAsText(f);
}
} else {
alert('Failed to load files');
}
}
document.getElementById('upfiles').addEventListener('change', readMultipleFiles, false);
readAsText() is an asynchronous operation, but you proceed with the AJAX call right away instead of waiting for the read operations to finish. That's why your console.log(masterFileArray) prints an empty array, when it runs none of the operations have finished and the array is still empty.
The best way to solve this is to wrap each file read operation in a promise and then proceed with the AJAX call once all these promises resolve.
Get rid of var masterFileArray = [] and change your code within the if (files) { ... } block to this:
Promise.all(files.map(function(f) {
return new Promise(function(resolve) {
var r = new FileReader();
r.onload = function (e) {
var contents = e.target.result;
resolve({name:f.name, contents: contents, type:f.type, size:f.size}); // resolve promise with object
};
r.readAsText(f);
});
})).then(function(masterFileArray) {
// All promises have resolved and their results have been collected in masterFileArray
console.log(masterFileArray);
new Ajax.Request('fileupload.php', {
method: 'post',
parameters: {files: JSON.stringify(masterFileArray)},
onSuccess: function(transport){
var response = transport.responseText;
console.log(response);
}
);
});
Hey guys I'm having an issue with file reader directive where on IE 11 I'm getting intermittent security error:
the directive code:
(function () {
var module = angular.module("new");
module.directive("freader", function () {
return {
scope: {
freader: "="
},
link: function (scope, element) {
element.bind("change", function (e) {
var reader = new FileReader();
var file = e.target.files[0];
var data = null;
file.size = file.date;
reader.onload = function (e) {
var array = new Uint8Array(e.target.result);
var result = Array.prototype.slice.call(array);
data = { data: result };
data.name = file.name;
if (data) {
scope.$apply(function() {
scope.freader = data;
});
}
}
if(file)
reader.readAsArrayBuffer(file);
});
}
}
});})();
As I researched so far I created clean function:
<input type="file" freader="vm.file" onclick="clean(this)" />
function clean(val) {
try {
val.value = null;
} catch (ex) { }
if (val.value) {
val.parentNode.replaceChild(val.cloneNode(true), val);
}
}
I have also tried to set the input type to text and then back again to file but nothing really works, error always shows up after some time.
Not really sure how to handle this problem?
i am new to coffeescript. i have already written code in js, now i want to convert it in coffeescript,i have try a lot,i have refer This also. but it won't help me.
here is my code,
this.$scope.callTestFuntion = function(){
this.blockingObject.render(function(dataURL){
console.log('via render');
console.log(dataURL.length);
});
}
this.$scope.blockingObject.callback=function(dataURL){
console.log('via function');
console.log(dataURL.length);
this.myCroppedImage = dataURL;
}
var handleFileSelect=function(evt) {
console.log('here');
var file=evt.currentTarget.files[0];
var reader = new FileReader();
reader.onload = function (evt) {
this.$scope.$apply(function($scope){
this.$scope.myImage=evt.target.result;
});
};
reader.readAsDataURL(file);
};
I want to convert it in coffeescript syntax. please help me.
Thanks
If you just want to convert the code then use http://js2.coffee
#$scope.callTestFuntion = ->
#blockingObject.render (dataURL) ->
console.log 'via render'
console.log dataURL.length
return
return
#$scope.blockingObject.callback = (dataURL) ->
console.log 'via function'
console.log dataURL.length
#myCroppedImage = dataURL
return
handleFileSelect = (evt) ->
console.log 'here'
file = evt.currentTarget.files[0]
reader = new FileReader
reader.onload = (evt) ->
#$scope.$apply ($scope) ->
#$scope.myImage = evt.target.result
return
return
reader.readAsDataURL file
return
# ---
# generated by js2coffee 2.2.0
Here is your converted code:
# CoffeeScript code converted from JavaScript
# from Georgi Naumov
# gonaumov#gmail.com for contacts and suggestions
#.$scope.callTestFuntion = ->
#.blockingObject.render (dataURL) ->
console.log 'via render'
console.log dataURL.length
#.$scope.blockingObject.callback = (dataURL) ->
console.log 'via function'
console.log dataURL.length
#.myCroppedImage = dataURL
handleFileSelect = (evt) ->
console.log 'here'
file = evt.currentTarget.files[0]
reader = new FileReader()
reader.onload = (evt) ->
#.$scope.$apply ($scope) ->
#.$scope.myImage = evt.target.result
reader.readAsDataURL file
And here is resulted JavaScript after compilation:
// Generated by CoffeeScript 1.12.3
(function() {
var handleFileSelect;
this.$scope.callTestFuntion = function() {
return this.blockingObject.render(function(dataURL) {
console.log('via render');
return console.log(dataURL.length);
});
};
this.$scope.blockingObject.callback = function(dataURL) {
console.log('via function');
console.log(dataURL.length);
return this.myCroppedImage = dataURL;
};
handleFileSelect = function(evt) {
var file, reader;
console.log('here');
file = evt.currentTarget.files[0];
reader = new FileReader();
reader.onload = function(evt) {
return this.$scope.$apply(function($scope) {
return this.$scope.myImage = evt.target.result;
});
};
return reader.readAsDataURL(file);
};
}).call(this);
I'm trying to remove duplicate JavaScript code. I have a page with many <input type="file">. Each loads an image and performs some distinct processing. The problem is that I have many duplicates of the following code:
inputFile1.onchange = function (e) {
var file = e.target.files[0];
if (typeof file == 'undefined' || file == null) {
return;
}
var imageType = /image.*/;
if (!file.type.match(imageType)) {
window.alert('Bad file type!');
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
var imageLoader = new Image();
imageLoader.onload = function () {
// process image
};
imageLoader.src = e.target.result;
};
reader.readAsDataURL(file);
};
inputFile2.onchange = ... (repeats all but process image)
inputFile3.onchange = ... (repeats all but process image)
Only the code at process image comment varies. How can I remove the surrounding duplicate code?
I know that JavaScript functions are objects. How can I define a function object and create one distinct instance for each event handler, passing a different function for process image to each object?
You can make a generator for such functions with a closure taking the individual callback as an argument:
function getChangeHandler(loadCallback) {
return function (e) {
var file = e.target.files[0];
if (typeof file == 'undefined' || file == null) {
return;
}
var imageType = /image.*/;
if (!file.type.match(imageType)) {
window.alert('Bad file type!');
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
var imageLoader = new Image();
imageLoader.onload = loadCallback; // <= uses the closure argument
imageLoader.src = e.target.result;
};
reader.readAsDataURL(file);
};
}
inputFile1.onchange = getChangeHandler(function() { /* custom process image */ });
inputFile2.onchange = getChangeHandler(function() { /* custom process image */ });
inputFile3.onchange = getChangeHandler(function() { /* custom process image */ });
An other, eventually superior approach would be to use only one change-event handler for all inputs, that dynamically chooses the custom image processor by the name or id of the input:
var imageProcessors = {
"box1": function() { … },
"anotherbox": function() { … },
…
};
function changeHandler(e) {
var input = this; // === e.target
…
reader.onloadend = function (e) {
…
imageLoader.onload = imageProcessors[input.id];
};
}
// and bind this one function on all inputs (jQuery-style):
$("#box1, #anotherbox, …").click(changeHandler);
You can write a function that returns a function:
function processFile(callback) { //callback is the unique file processing routine
return function(e) {
var file = e.target.files[0];
if (typeof file == 'undefined' || file == null) {
return;
}
var imageType = /image.*/;
if (!file.type.match(imageType)) {
window.alert('Bad file type!');
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
var imageLoader = new Image();
imageLoader.onload = callback; //Put it here!
imageLoader.src = e.target.result;
};
reader.readAsDataURL(file);
};
}
Then call like this:
inputFile1.onchange = processFile(function() {
//file processing for number 1
});
inputFile2.onchange = processFile(function() {
//file processing for number 2
});
inputFile3.onchange = processFile(function() {
//file processing for number 3
});
Here's an EMCA5 solution, just to throw it into the mix. It binds a dynamic event callback depending on the element.
I've assumed each field has an ID (input1 etc) but with some modification of the code (i.e. identifying the trigger element by some other means) this wouldn't be necessary.
Array.prototype.slice.call(document.querySelectorAll('input[type=file]')).forEach(function(element) {
/* prepare code specific to the element */
var input_specific_code = (function() {
switch (element.id) {
case 'input1': return function() { /* #input1 code here */ };
case 'input2': return function() { /* #input2 code here */ };
case 'input3': return function() { /* #input3 code here */ };
}
})();
element.addEventListener('change', (function(input_specific_code) { return function(evt) {
var id_of_trigger_input = element.id;
/* common code here */
/* element-specific code */
input_specific_code();
/* continuation of common code */
}; })(input_specific_code), false);
});