I have created an array to store a list of selected files. Well, I have to be honest, I looked up the code and when I realized it worked for my purpose, I used it. Now I need to access this array in order to delete some files manually, but I have tried using the index of each sector, but this does not work.
This is how i create the array and store files.
var files = [];
$("button:first").on("click", function(e) {
$("<input>").prop({
"type": "file",
"multiple": true
}).on("change", function(e) {
files.push(this.files);
}).trigger("click");
});
How could I read the array files[] if it contains an object fileList or obtain indexs from the array?
Here's how I understand your code:
Each time the first button in the dom is clicked a file input dialogue which accepts multiple files is generated. Upon return the dialogue emits a change event with a files variable (a FileList object) attached to the function context (this). Your code pushes the newly created FileList onto the files array. Since the input accepts multiple files each object pushed onto the files array is a FileList object.
So if you want to iterate through all elements in the files array you can put a function in the change event handler:
var files = [];
$("button:first").on("click", function(e) {
$("<input>").prop({
"type": "file",
"multiple": true
}).on("change", function(e) {
files.push(this.files);
iterateFiles(files);
}).trigger("click");
});
function iterateFiles(filesArray)
{
for(var i=0; i<filesArray.length; i++){
for(var j=0; j<filesArray[i].length; j++){
console.log(filesArray[i][j].name);
// alternatively: console.log(filesArray[i].item(j).name);
}
}
}
In the iterateFiles() function I wrote filesArray[i][j] isn't really a multidimensional array -- but rather a single dimensional array containing FileList objects which behave very much like arrays...except that you can't delete/splice items out of them -- they are read-only.
For more info on why you can't delete see: How do I remove a file from the FileList
Since you are using jQuery you can use $.grep
files=$.grep( files, function(elementOfArray, indexInArray){
/* evaluate by index*/
return indexInArray != someValue;
/* OR evaluate by element*/
return elementOfArray != someOtherValue;
});
API Reference: http://api.jquery.com/jQuery.grep/
Something like this?
for(var i = 0; i < files.length; i++) {
alert(files[i][0].name);
if (files[i][0].name == 'file.jpg') {
files.splice(i, 1) //remove the item
}
}
That is, there is always one file in each FileList due to the way you select it. So for each filelist you are only interested in the first file in it. For each file you can just get the properties as defined here: http://help.dottoro.com/ljbnqsqf.php
Related
I have a simple drag and drop page in my website. It allows dragging and dropping files, and below code gives me a list of dropped files.
var files = e.target.files || (e.dataTransfer && e.dataTransfer.files);
So far, so good. Problem is that when I drag and drop more files, that files object will not append to list of files I already had. Say, I dropped 2 files for the first time. files variable has 2 files in that case. If I drop a third file, e.target.files will have only the third file.
I tried creating a global variable and doing += to append file list. But javascript treats that variable as a string by default. So, var selectedFiles += e.target.files treats the file list as a string.
How can I make it so I have a list of files appended everytime a file is dropped?
Figured it out. Created a page level variable like so.
var selectedFiles = [];
And then used below code to push the files to this list.
var files = e.target.files || (e.dataTransfer && e.dataTransfer.files);
//Loop through all dropped files
for (var i = 0; i < files.length; i++) {
//Add files to the selected file list
selectedFiles.push(files[i]);
}
There is unnecessary looping, but I guess I can't fix that problem just yet.
You need to push each single file to your own list (array). MDN has a nice example for it. https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
var _Files = [];
function dragOverHandler(ev) {
// Prevent default behavior (Prevent file from being opened)
ev.preventDefault();
}
function dropHandler(ev) {
// Prevent default behavior (Prevent file from being opened)
ev.preventDefault();
if (ev.dataTransfer.items) {
// Use DataTransferItemList interface to access the file(s)
for (var i = 0; i < ev.dataTransfer.items.length; i++) {
// If dropped items aren't files, reject them
if (ev.dataTransfer.items[i].kind === 'file') {
var file = ev.dataTransfer.items[i].getAsFile();
_Files.push(file)
}
}
} else {
// Use DataTransfer interface to access the file(s)
for (var i = 0; i < ev.dataTransfer.files.length; i++) {
_Files.push(files[i])
}
};
console.log(_Files)
}
<div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
<p>Drag one or more files to this Drop Zone ...</p>
</div>
I have a FileList object which holds previously uploaded documents. I'm trying to use another function to add more files to this collection, by using another FileList object, so I need to "append" the secondary FileList object onto the primary one. How would it be possible to achieve this?
You have to first convert the FileList objects to Arrays, after which you can simply concat the multiple arrays.
const joined = Array.from(fileListA).concat(Array.from(fileListB));
const filesArray = [...filesList1, ...filesList2];
console.log(filesArray) // [File, File, File, File, File, ...]
The selected answer clarifies the path completely. A temp variable can also be used here, like the following:
var temp = files
files=Array.prototype.slice.call(temp).concat(Array.prototype.slice.call(event.target.files))
Also in React for setting the files in the state the following code can be used inside handleInputChange function:
var temp = this.state.files;
this.setState({
files: Array.prototype.slice.call(temp).concat(Array.prototype.slice.call(event.target.files))
})
var fileLists = [fileListA, fileListB];
var files = fileLists.reduce(function(a, c) {
return Array.prototype.concat.call(Object.values(a), Object.values(c))
})
Using JavaScript / jQuery, how can I get the complete file name of a file, when I only know its prefix?
For example:
The folder I'm browsing contains pic files:
001_PicA.jpg
002_PicB.jpg
004_PicC.jpg
007_PicD.jpg
008_PicE.jpg
Now let's say in my script I only have __002__ as information available. How could I get the complete file name (that is: 002_PicB.jpg)?
As other said, it is not possible to invoke directly. However if the list of files are available as an array then try the below approach.
Iterate each item in the array and then check for it occurance using idexOf().
var fileName = ["001_PicA.jpg", "002_PicB.jpg", "003_PicC.jpg"];
var contains = [];
$.each(fileName, function (i, j) {
if (j.indexOf("002") != -1) {
contains.push(j); //push the items to the array
}
});
console.log(contains); //returns 002_PicB.jpg
JSFiddle
I'm trying to use the Ajax File Upload as featured here: http://valums.com/ajax-upload/
As you can see, I need to create a qq.FileUploader object to initialize the script. However, I need to be able to dynamically create this objects without knowing the IDs of the elements. I've tried creating something like this:
var uploader, i = 0;
$(".file-upload").each(function() {
$e = $(this);
i++;
uploader[i] = new qq.FileUploader({
element: $(this)[0],
action: 'uploadfile.php',
allowedExtensions: ['doc', 'docx', 'pdf'],
multiple: false,
onComplete: function(id, fileName, responseJSON) {
$($e).siblings('input').val(responseJSON.newfilename);
}
});
});
I've learned that the [i] part I have added breaks the script, because I cannot have objects inside of an array.
Is there another way I can create this objects dynamically? They need to all have a unique name, otherwise the onComplete function gets overwritten for all of them. I experimented with using eval(), but I can't seem to make it work correctly.
You have to declare uploader as an array first :
var uploader = [];
Because you declared the variable without defining it, it has the default value of undefined , and your code was translated into something like undefined[i] which triggers an error.
Has to be something like
var uploader = {};
or else uploader is null and you cannot assign anything to it.
EDIT:
So there're two opitions, in my opinion, if one wants to have an array than it makes sense to declare one, var uploader = []; and then use the uploader.push() method or define it as an object var uploader = {}; and just do uploader[i] = ....
It is also possible to do the latter with an a array, but in the latter case I see no point in maintaining the counter (i).
I'm trying to figure out whether or not this is possible. First off, I should say that I'm cloning the FileReader object and maintaining that throughout my application (so I can allow the user to remove files before they officially upload them).
All that works fine, but I'm hung up trying to figure out the best way to allow a user to remove a member from this cloned object (members are the same as files [images in my case] which would be found within a normal FileReader object).
So basically I've cloned the object, add a pseudoHash to it which allows me to reference the cloned member that the user wants to delete, and upon clicking on a "Remove" icon, I search for the associated pseudoHash which I've tied to that icon, within the cloned object, and delete the member. The would work fine if the object were in its own function, but it's not. So I'm having trouble trying to delete the object's members. I made files global in this case, but it's still not working.
// Our FileList object
files = e.target.files;
// Create a clone since FileList is readonly
files = cloneObject(files);
// If files isn't empty, give the user the option to remove members
if (files.length) {
files = removeSelected(files);
}
Here is my function. Unfortunately when I click to remove an image from the "upload queue", it should go through this function, but it actually doesn't delete the object, as I know Javascript doesn't ever completely delete objects, so if it's the last member, I try setting it to an empty object, but that doesn't work. If it's not the last member, I just want to remove it within its place. Again, because this is in a separate function and not the parent, it's only deleting the local reference to the variable.
// Remove selected file from cloned fileList object
var removeSelected = function(files) {
var dataPseudoHash = $(this).attr('data-pseudo-hash');
$('#js-selected-files').delegate('.js-remove-selected', 'click', function() {
if (files.length == 1) {
$('.js-image-upload').attr('disabled', true).addClass('btn_disabled');
files = {};
delete files;
} else {
// Loop through our files object and if we find a member with the same
// pseudoHash as the attribute from whatever 'X' icon that was clicked, remove it
$.each(files, function(i, dataPseudoHash) {
if (files[i].pseudoHash == dataPseudoHash) {
delete files[i];
files.length -= 1;
}
});
}
// Remove hidden input that prevents duplicate files being uploaded of
$('.js-pseudo-hash[value="' + dataPseudoHash + '"]').remove();
$(this).parent().fadeOut('normal', function() {
$(this).remove();
});
return files;
};
What's the best way to handle this? Maybe setting a flag to true or false, and then delete the object or its members accordingly in the parent function depending on the case? Not quite sure. Other than that, I've got it uploading the files fine, but I need to find out how to remove properties of the object or the object altogether (if all "Remove" icons are clicked).
Firstly you should know that the delete operator deletes only an element oof an array or element of an object not the whole array. In your first if condition
if (files.length == 1) {
$('.js-image-upload').attr('disabled', true).addClass('btn_disabled');
files = {};
delete files;
}
You are deleting the whole object which returns false.
Now it will be better if you can manually check whether the second if condition is true or not in any case.