ng2-file-upload single upload override file upload - javascript

I do the demo base on this tutorial: https://github.com/valor-software/ng2-file-upload. I want to single file upload but without remove file button. By adding the File A, after that I add the File B. File A will be replaced by file B. here is my uploader:
this.uploader = new FileUploader(
{
url: this.baseURL,
allowedFileType: ["xls"],
maxFileSize: 5,
queueLimit: 1
});
Please advice me

As Arun Muthiyarkath suggested, you can use the onAfterAddingFile, but the shorter code would be:
ngOnInit() {
this.uploader.onAfterAddingFile = (fileItem: FileItem) => {
if (this.uploader.queue.length > 1) {
this.uploader.removeFromQueue(this.uploader.queue[0]);
}
};
}
Source: https://github.com/valor-software/ng2-file-upload/issues/703

Probably you can use onAfterAddingFile callback of the library provided function. Below is the sample code. This is always override old file with latest file and queue will always contain one item which is the latest file.
ngOnInit() {
this.uploader.onAfterAddingFile = (fileItem: FileItem) => this.onAfterAddingFile(fileItem)
}
onAfterAddingFile(fileItem: FileItem) {
let latestFile = this.uploader.queue[this.uploader.queue.length-1]
this.uploader.queue = [];
this.uploader.queue.push(latestFile);
}

this.uploader.onAfterAddingFile = (fileItem: FileItem) => {
if (this.uploader.queue.length > 0) {
this.uploader.queue = [fileItem];
}
};

Related

Cannot iterate over file list from dropped elements in browser web page with DataTransfer

There are similar questions like this, but they don't explain why this fails.
After dropping multiple files into the browser, iterating with the for...of statement fails while the normal for loop works.
The for...of version outputs undefined for file.name while the normal for version outputs the filename correctly.
Why?
function initDragDropEvents() {
// Trigger file uploads on drop events.
$('body').on('drop', function(e) {
let fileList = getFileListFromDropEvent(e.originalEvent);
// Have image? Update view.
for (const file in fileList) {
console.log('1 Dropped file: ' + file.name);
}
for (let i = 0; i < fileList.length; i++) {
console.log('2 Dropped file: ' + fileList[i].name);
}
});
}
function getFileListFromDropEvent(event) {
// Prevent default behavior, which opens the file.
event.preventDefault();
// Set default result for file.
let fileList = [];
// Get item list from #event.
let itemList = event.dataTransfer.items;
if (!itemList) {
itemList = event.dataTransfer.files;
}
if (itemList) {
for (const item of itemList) {
// Assume DataTransfer interface by default.
let file = item;
// Use DataTransferItemList interface instead?
if (item.kind === 'file') {
file = item.getAsFile();
}
fileList.push(file);
}
}
return fileList;
}
This was caused by a subtle bug. Rather than delete the question, will post the answer in case someone else makes the same mistake in the future.
This works if you use for...of and not for...in.

Convert Image as File Type in Angular

I am modifying a method a in angular typescript where it was uploading an image using input element of type file and in the method event was getting passed. I have to modify a method as there is no input element now and I have a image file in my assets folder of angular project. So now I don't want to tamper the previously written code:
loadImages(event) {
const files = event.target.files;
if (this.CheckFileName(files[0].name) && this.CheckFileSize(files[0].size)) {
let imageList = [];
const fileList: Array<File> = Array.from(files);
fileList.sort((a, b) => {
if (a.name > b.name)
return 1;
if (b.name > a.name)
return -1;
return 0;
})
}
And now I want my file to be from "../../assets/images/0001.png".
How could I achieve the same by reading my image file from the given path and converting it to type File.
You can use fetch the image then convert it to the File object.
You will need to return an Observable instead of returning the value directly.
getImage() {
return this.http
.get("https://picsum.photos/id/34/200/300", {
responseType: "arraybuffer"
})
.pipe(
map(response => {
return new File([response], "myImage.png");
})
);
}
You can check a working demo here.

Why doesn't my .JSX script recognize every image in a folder which I want to mass-resize?

I have this JSX script I created but I feel like it's not checking for every file type in the filelist variable. Can someone take a look? It's very frustrating when I have it running and then for some reason a non-descript error message pops up and then it stops
Here is the script:
var inputFolder = Folder.selectDialog("Select a folder to process"),
fileList = inputFolder.getFiles(/\.(jpg|tif|psd|crw|cr2|nef|dcr|dc2|raw)$/i);
for(var i=0; i < fileList.length; i++) {
var doc = open(fileList[i]);
if(doc.width !== doc.height) {
if(doc.width > doc.height) {
doc.resizeCanvas(doc.width, doc.width)
} else {
doc.resizeCanvas(doc.height, doc.height)
}
}
if((doc.width && doc.height) > 1000) {
doc.resizeImage(1000, 1000);
} else {
doc.resizeImage(doc.width, doc.height);
}
doc.save();
doc.close();
}
This is the error message:
It seems that Folder.getFiles() doesn't accept RegExp objects, it only accepts a string or a function, beside that, it will also include Folder objects, you can change it to something like this to filter only files and only the file types you're interested in:
function filter(file) {
return (file instanceof File && /\.(jpg|tif|psd|crw|cr2|nef|dcr|dc2|raw)$/i.test(file.name))
}
fileList = inputFolder.getFiles(filter);

Javascript file dropping and reading directories - Asynchronous Recursion

So I'm trying to create a file dropper web application. Right now, a user can drop files on the screen and I can read them, including all the files in a directory that was dropped. But, I don't know when the script is done reading the files.
Some code:
This first function handles a 'drop' event and will loop through each file and send it to another function that will read its contents.
function readDrop( evt )
{
for( var i = 0; i < evt.dataTransfer.files.length; i++)
{
var entry = evt.dataTransfer.items[i].webkitGetAsEntry();
if(entry)
readContents(entry, "");
}
//Do stuff after all files and directories have been read.
}
This function is a recursive FileEntry reader. If it is a file, I will read the FileEntry. If it is a directory, it will loop through the contents and pass it through this function.
function readContents(entry, path)
{
if( entry.isFile )
{
readFileData( entry, path, function(fileData)
{
_MyFiles.push( fileData );
});
}
else if( entry.isDirectory )
{
var directoryReader = entry.createReader();
var path = path + entry.name;
directoryReader.readEntries(function(results)
{
for( var j = 0; j < results.length; j++ )
{
readContents(entry, path);
}
}, errorHandler)
}
}
And here is my function for reading the files. The callback just pushes the fileData object to a global array
function readFileData(entry, path, callback)
{
var fileData = {"name": entry.name, "size": 0, "path": path, "file": entry};
entry.file(function(file)
{
fileData["size"] = file.size;
callback( fileData );
}
}
I'm not sure where to go from here so that I can have a callback when all files and directories have been read.
The FileSystem API doesn't seem well suited for the task of a full recursive traversal, perhaps that's part of the reason why other vendors are not adopting it. Anyway, with an arcane combination of Promises I think I was able to accomplish this goal:
function traverse_directory(entry) {
let reader = entry.createReader();
// Resolved when the entire directory is traversed
return new Promise((resolve_directory) => {
var iteration_attempts = [];
(function read_entries() {
// According to the FileSystem API spec, readEntries() must be called until
// it calls the callback with an empty array. Seriously??
reader.readEntries((entries) => {
if (!entries.length) {
// Done iterating this particular directory
resolve_directory(Promise.all(iteration_attempts));
} else {
// Add a list of promises for each directory entry. If the entry is itself
// a directory, then that promise won't resolve until it is fully traversed.
iteration_attempts.push(Promise.all(entries.map((entry) => {
if (entry.isFile) {
// DO SOMETHING WITH FILES
return entry;
} else {
// DO SOMETHING WITH DIRECTORIES
return traverse_directory(entry);
}
})));
// Try calling readEntries() again for the same dir, according to spec
read_entries();
}
}, errorHandler );
})();
});
}
traverse_directory(my_directory_entry).then(()=> {
// AT THIS POINT THE DIRECTORY SHOULD BE FULLY TRAVERSED.
});
Following on from the answer by drarmstr, I modified the function to be compliant with the Airbnb ESLint standards, and wanted to make some further comments on its usage and results
Here's the new function:
function traverseDirectory(entry) {
const reader = entry.createReader();
// Resolved when the entire directory is traversed
return new Promise((resolve, reject) => {
const iterationAttempts = [];
function readEntries() {
// According to the FileSystem API spec, readEntries() must be called until
// it calls the callback with an empty array. Seriously??
reader.readEntries((entries) => {
if (!entries.length) {
// Done iterating this particular directory
resolve(Promise.all(iterationAttempts));
} else {
// Add a list of promises for each directory entry. If the entry is itself
// a directory, then that promise won't resolve until it is fully traversed.
iterationAttempts.push(Promise.all(entries.map((ientry) => {
if (ientry.isFile) {
// DO SOMETHING WITH FILES
return ientry;
}
// DO SOMETHING WITH DIRECTORIES
return traverseDirectory(ientry);
})));
// Try calling readEntries() again for the same dir, according to spec
readEntries();
}
}, error => reject(error));
}
readEntries();
});
}
here's a drop event handler:
function dropHandler(evt) {
evt.preventDefault();
const data = evt.dataTransfer.items;
for (let i = 0; i < data.length; i += 1) {
const item = data[i];
const entry = item.webkitGetAsEntry();
traverseDirectory(entry).then(result => console.log(result));
}
}
The result variable at the end contains an array, mirroring the tree structure of the folder you dragged and dropped.
For example, here is a git repo for my own site, ran through the above code:
Here's the Git repo for comparison https://github.com/tomjn/tomjn.com

Why does the following javascript snippet produce an empty zip archive?

The snippet below is using zip.js to create a zip archive, ZippyMcZip.zip or the Strings in contents. contents is an array of values. e.g.
{name:"my name",contents:"contents to write to file."}
The archive is being created, however apart from the manifest it is empty:
$ unzip -l ZippyMcZip.zip
Archive: ZippyMcZip.zip
Length Date Time Name
-------- ---- ---- ----
0 05-01-13 16:41 File1.txt
0 05-01-13 16:41 File2.txt
-------- -------
0 2 files
Does anyone have any pointers as to why the archive would contain empty files?
saveAs is provided by FileSaver.js, I don't think it is an issue as the file is being written to the HD and it being used elsewhere.
function createZip(contents) {
function onProgress(a,b) {
console.log("current",a, "end",b);
}
function onEnd() {
console.log("on End");
}
zip.workerScriptsPath = "/js/zip/";
zip.useWebWorkers = false;
var zipper = (function() {
var zipWriter;
return {
addTexts: function(files) {
function add(text) {
zipWriter.add(text.name,
new zip.TextReader(text.contents),onEnd,onProgress);
}
zip.createWriter(new zip.BlobWriter(), function(writr) {
zipWriter = writr;
});
_.foreach(files, add);
},
getBlob: function(callback) {
zipWriter.close(callback);
}
};
})();
zipper.addTexts(contents);
zipper.getBlob(function(blob) {
saveAs(blob, "ZippyMcZip.zip");
});
}
You have 2 issues related to the asynchronous nature of zip.js API.
First, you try to write multiple files in parallel: it won't work. So, instead of iterating with the synchronous _.foreach function, you have to call the add function recursively in the onEnd callback of zipWriter.add method (cf. [1]).
Then, you also have to wait for this content to be written before calling zipWriter.close method, so you have to define a callback parameter (cf. [2]) in the signature of addTexts method. It is called when the recursive process is finished.
Here is your code with these 2 fixes:
function createZip(contents) {
function onProgress(a, b) {
console.log("current", a, "end", b);
}
zip.workerScriptsPath = "/js/zip/";
zip.useWebWorkers = false;
var zipper = (function() {
var zipWriter;
return {
addTexts : function(files, callback /* [2] new parameter */) {
function add(fileIndex) {
if (fileIndex < files.length) {
zipWriter.add(files[fileIndex].name,
new zip.TextReader(files[fileIndex].contents), function() {
add(fileIndex + 1); /* [1] add the next file */
}, onProgress);
} else {
callback() /* [2] no more files to add: callback is called */;
}
}
zip.createWriter(new zip.BlobWriter(), function(writer) {
zipWriter = writer;
add(0); /* [1] add the first file */
});
},
getBlob : function(callback) {
zipWriter.close(callback);
}
};
})();
zipper.addTexts(contents, function() {
zipper.getBlob(function(blob) {
saveAs(blob, "ZippyMcZip.zip");
});
});
}

Categories