Sort input files after selection - javascript

Is there any way for me to sort files for POST to server using any client side solution?
More specific, i am using the following tag <input type="file" name="Myfiles[]" multiple> To choose some images.
With the code at the end i display a preview of the images and using jQuery UI sortable i'm able to change the position of the elements.
So, when i post the data to the server how can i insert the files in the order of the sort? that's the point where i'm stuck
for(var i = 0; i< this.files.length; i++)
{
var file = this.files[i];
if(!file.type.match(‘image’))
continue;
var picReader = new FileReader();
picReader.addEventListener('load',function(event){
var picFile = event.target;
$('#sortable').append('<li><img height="100" width="100" src="'+picFile.result+'" /></li>');
});
picReader.readAsDataURL(file);
}

Assuming you are storing the files into an array:
var storedFiles = [];
You can create a hidden field to store the IDs of the images in the order you want (3,1,2,4..) These IDs must be generated after your images are selected.
Then when the upload button is clicked, grab the sorted contents of the hidden input field and run a for loop to reprocess the order of the files.
var data = new FormData();
var items_array = $('.cvf_hidden_field').val();
var items = items_array.split(',');
for (var i in items){
var item_number = items[i];
data.append('files' + i, storedFiles[item_number]);
}
Then append the sorted files into the variable data, then send it using AJAX:
$.ajax({
url: 'upload.php',
type: 'POST',
contentType: false,
data: data,
processData: false,
cache: false,
success: function(response, textStatus, jqXHR) {}
});

The order in which the server receives the files will be the order in which they were placed in the form to be submitted to the server.
That means it's probably easier to re-order them client-side before submitting e.g. by re-ordering the order in which they appear in the form for submission. Heres a rough-and-ready snippet of what you could use:
var newOrder = [];
for(var i = 0; i< this.files.length; i++){
var indiv_file = this.files[a];
// processing to calculate desired array position for submission
idealPos = function_returning_new_array_position(indiv_file);
newOrder[idealPos] = this.files[a];
}
Thus re-order your 'this.files' array to reflect your chosen order. And use the newOrder array in the form when you submit the files. I can't quite make out what you're doing in the above code, but unless your users are expecting their images to be re-ordered, it could turn out a bit disorienting to see the files they are planning to submit jumping around.

You can use plain JavaScript code to sort the files using the file names and store them as an array.
var files = evt.target.files
var RESULT = []
var m = files.length
for (var a = 0; a < m; a++) {
var min = 0
for (var b = 0; b < (m - 1) - a; b++) {
if ((files[b].name).localeCompare(files[b + 1].name) == 1) {
min = b + 1
}
}
RESULT[a] = files[min]
delete files[min]
}
The above code sorts the uploaded files in ascending order based on the file name and stores it in RESULT.

Related

Google Apps Script - XML Parser - Regex

I am using a Google Apps Script that pulls the content from a feed in a sheet.
This is the code that I'm using:
function processXML(FeedURL,sheetsFileDestinationURL,rawPasteSheetName,OPT_childNamesArray,OPT_Namespace){
var OPT_childNamesArray = ["link"]; // get only item url from the feed
var GoogleSheetsFile = SpreadsheetApp.openByUrl(sheetsFileDestinationURL);
var GoogleSheetsPastePage = GoogleSheetsFile.getSheetByName(rawPasteSheetName);
if (OPT_childNamesArray){
GoogleSheetsPastePage.getDataRange().offset(1,0).clearContent(); // get all filled cells, omitting the header row, and clear content
}
else {
GoogleSheetsPastePage.getDataRange().offset(0,0).clearContent(); // get all filled cells, INCLUDING the header row, and clear content
}
// Generate 2d/md array / rows export based on requested columns and feed
var exportRows = []; // hold all the rows that are generated to be pasted into the sheet
var XMLFeedURL = FeedURL;
var feedContent = UrlFetchApp.fetch(XMLFeedURL).getContentText(); // get the full feed content
var feedItems = XmlService.parse(feedContent).getRootElement().getChild('channel').getChildren('item'); // get all items in the feed
for (var x=0; x<feedItems.length; x++){
// Iterate through items in the XML/RSS feed
var currentFeedItem = feedItems[x];
var singleItemArray = []; // use to hold all the values for this single item/row
// Parse for specific children (requires names and namespace)
if (OPT_childNamesArray){
for (var y=0; y<OPT_childNamesArray.length; y++){
// Iterate through requested children by name and fill rows
var currentChildName = OPT_childNamesArray[y];
if (OPT_Namespace){
if (currentFeedItem.getChild(OPT_childNamesArray[y],OPT_Namespace)){
singleItemArray.push(currentFeedItem.getChildText(OPT_childNamesArray[y],OPT_Namespace));
}
else {
singleItemArray.push("null");
}
}
else {
if (currentFeedItem.getChild(OPT_childNamesArray[y])){
singleItemArray.push(currentFeedItem.getChildText(OPT_childNamesArray[y]));
}
else {
singleItemArray.push("null");
}
}
}
exportRows.push(singleItemArray);
}
// Parse for ALL children, does not require knowing names or namespace
else if (!OPT_childNamesArray){
var allChildren = currentFeedItem.getChildren();
if (x == 0){
// if looking at first item, create a header row first with column headings
var headerRow = [];
for (var h=0; h<allChildren.length; h++){
headerRow.push(allChildren[h].getName());
}
exportRows.push(headerRow);
}
for (var c=0; c<allChildren.length; c++){
singleItemArray.push(allChildren[c].getText());
}
exportRows.push(singleItemArray);
}
}
// Paste the generated md array export into the spreadsheet
if (OPT_childNamesArray){
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValues(exportRows);
}
else if (!OPT_childNamesArray){
var maxRangeLength = 0;
var currentRowIndex = 1;
for (var x = 0; x<exportRows.length; x++){
if (exportRows[x].length > maxRangeLength){
maxRangeLength = exportRows[x].length;
}
GoogleSheetsPastePage.getRange(currentRowIndex,1,1,exportRows[x].length).setValues([exportRows[x]]);
currentRowIndex++;
}
}
}
My problem is this:
When I run this code I get:
https://url/115-396/
https://url/115-396/
https://url/115-396/
I need to remove "115-396/".
So I tryed to add this code but didn't work:
...
// Paste the generated md array export into the spreadsheet
if (OPT_childNamesArray){
for (var k = 0; k < exportRows.length; k++) {
var re = '115-396/'
var replacingItem = '';
var URL = exportRows[0].toString().replace(re, replacingItem);
}
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValue(URL);
}
else if (!OPT_childNamesArray){
...
Edit after #Yuri reply:
// Paste the generated md array export into the spreadsheet
if (OPT_childNamesArray){
for ( k=0; k < exportRows[0].length; k++) {
var re = '115-396/'
var replacingItem = '';
exportRows[0][k] = exportRows[0][k].toString().replace(re, replacingItem);
}
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValues(exportRows);
}
result:
https://url/
https://url/115-396/
https://url/115-396/
Basically, the regex is applied only to the first url.
How I can make that the regex is applied to all the url's?
Any help?
Thanks
You are using a for to iterate thru the exportRow array, but later on, you're not using the k iterator inside the for.
Then, you are not accessing the exportRows array, only the first position:
var URL = exportRows[0].toString().replace(re, replacingItem);
Shouldn't be?
var URL = exportRows[k].toString().replace(re, replacingItem);
In that case, it won't work, because URL it's not an array, so by doing this you are only saving the last assignation produced on the for iterator on the URL, I believe you are trying to do the following:
for ( k=0; k < exportRows.length; k++) {
var re = '115-396/'
var replacingItem = '';
exportRows[k] = exportRows[k].toString().replace(re, replacingItem);
}
And you'll have exportRows as an array of the desired url's without the 115-396 extensions.
Now you can place this on the spreadsheet with setValue as you were doing, but setValue is for strings, integers, etc, and not for arrays. For arrays you have setValues()
GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length).setValues(exportRows);
But, then, the range of exportRows should match the range of your getRange selection, which I'm not sure it's happening.
Just to clarify it, exportRows.length is the length of the array, and exportRows[1] is the length of the string/url stored on the position 1 of the array.
Hope this helps, the question is not really clear neither the intentions, provide more info if still not working.
How to know the size of the range you're getting?
var myrange = GoogleSheetsPastePage.getRange(2,1,exportRows.length,exportRows[1].length)
Logger.log(myrange.getNumRows());
Logger.log(myrange.getNumColumns());
You'll be able to know the range you have on getRange and make it match with the exportRows size.
Make sure to check the attached documentation, and in case you have more doubts please open a new question related to it.

Obtain list of files from input

I have this input <input type="file" id="file" name="file" accept="image/*" multiple> this allow the user select several images and I need to pass all of them to my FormData so I do this:
var formdata = new FormData();
var files = $('#file')[0].files[0];
formdata.append('file',files);
But that only take the first image from de list, How can i take all the images and store all of them in var files?
Thanks in advance
EDIT: The backend I use is django/python and if I use this way in my backend detect only one image from the list like this [<InMemoryUploadedFile: img.png (image/png)>] and using just var files = $('#file')[0].files; show me nothing.
There are many problems:
You can't redeclare the same variable if you want to keep its previous values
You need to change the index so that it's not saving to the same spot
$("#file") - shouldn't be an array, it's an object so i'm surprised it's not throwing an error
Let's say your code is legit. You could do this:
var files=[];
var length = $("#file").length;
for (i = 0; i < length; i++) {
files[i] = $('#file')[i];
}
formdata.append('file',files);
This was my solution
var formdata = new FormData();
var files=[];
var count = document.getElementById('file').files.length;
for (i = 0; i < cont; i++) {
files[i] = document.getElementById('file').files[i];
formdata.append('file',files[i]);
}
Using JQuery for length only brings me 1 element and gives me more problems so
I use puere JavaScript for this part and works fine

Controller does not catch JavaScript variable

I am working in ASP.NET Boilerplate (ABP) and AngularJS. I am using controllers (to upload files) with Kendo upload on frontend. To access controller I am using clicking kendo button clicking it like:
($("#files").data("kendoUpload")).options.async = vm.uploadOptions(onUpdate);
$('.k-upload-selected').click();
Function vm.uploadOptions(onUpdate) takes list of Ids and returns retObject like
var retObject = { saveUrl: '/ControllerName/ActionName?id=15&id=16', autoUpload: false, batch: true }
Now the actual question:
When I assign saveUrl in retObject like above or like
retObject.saveUrl = '/ControllerName/ActionName?id=195&id=196&id=197'
(ids hardcoded), the controller is entered (I have a breakpoint there) and I have a C# List with two elements.
When I assign url like:
vm.url = '/ControllerName/ActionName?fileId=' + fileIds[0];
len = fileIds.length;
for (var i = 1; i < len; i++) {
vm.url += '&fileId=' + fileIds[i];
}
retObject.saveUrl = vm.url;
the controller is not entered.
Finally (this is what I use in code now), when I assign like
vm.url = '?fileId=' + fileIds[0];
len = fileIds.length;
for (var i = 1; i < len; i++) {
vm.url += '&id=' + fileIds[i];
}
retObject.saveUrl = '/ControllerName/ActionName' + vm.url;
it does work - controller is entered with a proper list of ids.
When I copied dynamically generated (not working) string and assigned it as hardcoded it started working.
Why it happens, I mean: why exactly the same string initialized in different ways makes different results?

How to give a custom name to the objects in an array?

I have an upload form and for adding and deleting the files in a filelist I created an array that contains the files to send them in one request.
Creating the array
var filelist = [];
for(var i = 0; i < data.files.length; i++){
filelist.push(data.files[i]);
console.log(filelist);
}
Result in console
[File, File, File]
The files are contained in the array but now I want to give the names in the array the names of the files for deleting purposes.
So instead of [File, File, File], I would like to have for example [image01.jpg, image02.jpg, image03.jpg]
I have already tried
filelist.push(data.files[i].name);
result
["image01.jpg", "image02.jpg", "image03.jpg"]
But the files aren't added to the array? Can anybody help me with this please?
The reason I'm doing this is because I would like to try to remove files from the array on value and not on index.
code for deleting the files from the array
var idx = filelist.indexOf(file.name);
filelist.splice(idx,1);
You can set the name of the file as a key:
var filelist = {};
for(var i = 0; i < data.files.length; i++) {
var file = data.files[i];
filelist[file.name] = file;
}
And then use the delete operator to delete the file based on its name:
var filename = fileToDelete.name;
delete filelist[filename];

How to save a HTMLElement (Table) in localStorage?

I've been trying this for a while now and could not find anything online...
I have a project, where tablerows get added to a table. Works fine.
Now I want to save the Table in the localStorage, so I can load it again. (overwrite the existing table).
function saveProject(){
//TODO: Implement Save functionality
var projects = [];
projects.push($('#tubes table')[0].innerHTML);
localStorage.setItem('projects', projects);
//console.log(localStorage.getItem('projects'));
The problem is the Array "projects" has (after one save) 2000+ elements. But all I want is the whole table to be saved to the first (or appending later) index.
In the end I want the different Saves to be listed on a Option element:
function loadSaveStates(){
alert('loading saved states...');
var projects = localStorage.getItem('projects');
select = document.getElementById('selectSave'); //my Dropdown
var length = projects.length,
element = null;
console.log(length);
for (var i = 0; i < length; i++) {
element = projects[i];
var opt = document.createElement('option');
opt.value = i;
opt.innerHTML = 'project ' + i;
select.appendChild(opt);
}
}
Can anyone tell me what I am doing wrong?
You can easily do this by jquery, are you interested in this, if yes.. then try following code
For setting the value
$.jStorage.set("projects", $.trim(projects));
For Getting the data
$.jStorage.get("projects");
For deleting the data with key
$.jStorage.deleteKey("projects");
I coose to stay with localStorage, but insted of using an Array I just let the user give every project a name and create a new Item for every Save:
function saveProject(){
//TODO: Implement Save functionality
var pname=prompt("Please enter your project name:","projectname")
var text = $('#mainTable')[0].innerHTML;
//console.log(text);
localStorage.setItem(pname, text);
//console.log(localStorage.key(2));
loadSaveStates();
}
function loadProject(){
var selected = $('#selectSave')[0].selectedIndex
//console.log(selected);
if (localStorage.key(selected) == 'jStorage'){
selected++;
}
var innerHTMLTable = localStorage[localStorage.key(selected)];
//console.log(innerHTMLTable);
$('#mainTable')[0].innerHTML = innerHTMLTable;
updateHandlers();
}
function deleteProject(){
var selected = $('#selectSave')[0].selectedIndex
var pname = $('#selectSave')[0].options[selected].value
$('#selectSave')[0].remove(selected);
localStorage.removeItem(pname);
//console.log(pname);
loadSaveStates();
}

Categories