Multiple Instances of Ajax Uploader on the Same Page - javascript
I developed an ajax file uploader and it works great if the one instance is on the page. I'm trying to convert it to allow multiple instances, and it almost works, EXCEPT, when I'm uploading multiple files in one form, it uploads the first file fine, but then for all subsequent files, for some reason it points forward to the next file reader from the second form instance. If I upload using the last (second) instance of the upload form, multiple files upload fine. But if I try uploading with the first instance, it will upload the first file, but all subsequent files get sent to the empty file input from the second instance. I can't understand why. I'm using unique id names throughout the upload form and referencing that unique id throughout the javascript functions. I'll try to include all the necessary bits of code below.
The forms are generated by PHP. The php var $uid is a randomly generated unique id that I use throughout. First, the initialization of the upload function is output to the page in a <script> tag:
'<script> '.
'jQuery(document).ready(function($){ '.
'var myup_'.$uid.' = new MyUp({ '.
'form_id: "myup_form_'.$uid.'", '.
'uid: '.$uid.', '.
'container: "'.$name.'", '.
'table: "'.$style.'", '.
'iconcolor: "'.$iconcolor.'", '.
'maxsize: '.$maxsize.', '.
'permitted: '.$permitted.', '.
'prohibited: '.$prohibited.', '.
'fixed: '.$fixedsetting.', '.
'pathcheck: "'.$pathcheck.'", '.
'uploader: '.$uploader.', '.
'loading: "'.my_url.'/lib/img/ajax.gif" '.
}); '.
'}); '.
'</script>';
Obviously all those variables for my settings are defined earlier. With multiple instances on the page, it reads the settings correctly for each different instance. They are successfully showing up with different styles, icon colors, file type permissions, max file size settings, etc. All that works with multiple instances.
Now the form:
'<div class="myup_container" style="'.$inlinestyle.'">'.
'<form name="myup_form_'.$uid.'" id="myup_form_'.$uid.'" action="javascript:void(0);" enctype="multipart/form-data">'.
'<input type="hidden" id="upload-actionpath-'.$uid.'" value="'.$fixed.'" data-basename="'.$basename.'" data-start="'.$start.'" />'.
'<div class="myup_buttons_container" style="text-align:right;">'.
'<span class="myup_wrapper" style="text-align:left;">'.
'<input type="file" name="myup_files_'.$uid.'[]" id="myup_files_'.$uid.'" class="hidden_browse"'.$multiple.' />'.
'<span class="add_files">'.$addfiles.'</span>'.
'<span id="submit_upload_'.$uid.'">'.$uploadlabel.'</span>'.
'</span>'.
'</div>'.
'</form>'.
'<div id="myup_files_container_'.$uid.'" class="myup_files_container"></div>'.
'<span id="my_removedfiles_'.$uid.'" style="display:none;"></span>'.
'</div>';
So that's a pared down version of it. The instance in the script tag, containing the settings, and the html form, are output by a shortcode. So multiple shortcodes on the page will output multiple instances of the MyUp function.
Here's what I hope are all the pertinent bits of the javascript functions (it's long, sorry, but I removed a ton of stuff):
jQuery(document).ready(function($)
{
// throughout, the var fuid will refer
// to the php var $uid from the html form and instance settings
function myupRemove(id, filename, fuid)
{
// handle files the user removes from the input field
// before submitting the upload
}
function MyUp(config)
{
this.settings = config;
this.fuid = this.settings.uid;
this.file = "";
this.browsed_files = [];
var self = this;
MyUp.prototype.myupDisplay = function(value)
{
this.file = value;
if(this.file.length > 0)
{
/* this is a really long bit of code
* that i'll spare you, but basically I iterate
* through all the files in the input field
* and put them dynamically into a table
* and drop the table onto the page
* so the user can rename them, remove them before upload,
* and then watch the status bar for each file as it uploads.
* This portion of the code works fine with multiple instances.
*/
}
}
// Create Unique ID
MyUp.prototype.uid = function(name)
{
// Here I generate a unique ID for each file,
// and prepend it with the Instance's unique id (i.e., this.fuid)
return this.fuid+'_'+name.replace(/[^a-z0-9\s]/gi, '_').replace(/[_\s]/g, '_');
}
// Get File Extension
MyUp.prototype.ext = function(file, lowercase)
{
return (/[.]/.exec(file)) ? (lowercase ? /[^.]+$/.exec(file.toLowerCase()) : /[^.]+$/.exec(file)) : '';
}
// Format File Size
MyUp.prototype.nicesize = function(fileSize)
{
// a bunch of code to format the file size then...
return niceSize;
}
// Attribute FileType Icons
MyUp.prototype.icon = function(icon_ext, color)
{
// a bunch of arrays to determine
// which file type icon to display in the table
}
//File Reader
MyUp.prototype.read = function(e)
{
if(e.target.files)
{
// references the myupDisplay function
// where I add the files to a table
self.myupDisplay(e.target.files);
self.browsed_files.push(e.target.files);
}
}
function addEvent(type, el, fn)
{
if(window.addEventListener)
{
el.addEventListener(type, fn, false);
}
else if(window.attachEvent)
{
var f = function()
{
fn.call(el, window.event);
};
el.attachEvent('on' + type, f)
}
}
// Collect File IDs and Initiate Upload for Submit
MyUp.prototype.starter = function()
{
if(window.File && window.FileReader && window.FileList && window.Blob)
{
var browsed_file_id = $("#"+this.settings.form_id).find("input[type='file']").eq(0).attr("id");
document.getElementById(browsed_file_id).addEventListener('change', this.read, false);
document.getElementById('submit_upload_'+this.fuid).addEventListener('click', this.submit, true);
}
else alert(browser_cant_read_message);
}
// Begin Upload on Click
MyUp.prototype.submit = function()
{
self.begin();
}
// Initiate Upload Iterator
MyUp.prototype.begin = function()
{
if(this.browsed_files.length > 0)
{
for(var k=0; k<this.browsed_files.length; k++)
{
var file = this.browsed_files[k];
this.myupAjax(file,k);
}
this.browsed_files = [];
}
else alert(no_files_chosen_message);
}
// Ajax Upload
MyUp.prototype.myupAjax = function(file,i)
{
if(file[i]!== undefined)
{
var id = file_id = self.uid(file[i].name),
rawname = file[i].name.substr(0, file[i].name.lastIndexOf('.')) || file[i].name,
extension = self.ext(file[i].name, false),
browsed_file_id = $("#"+this.settings.form_id).find("input[type='file']").eq(0).attr("id");
path = this.settings.fixed ? this.settings.fixed : String($('input#upload-actionpath-'+this.fuid).val()),
pathcheck = String(this.settings.pathcheck),
removed_file = $("#"+id).val(),
newname = String($('input#rename_upfile_id_'+id).val()),
new_name = newname === '' || newname === 'undefined' || newname === undefined ? file[i].name : newname+'.'+extension,
removed = this.settings.removed,
loading = this.settings.loading,
fixedchars = this.settings.fixed;
// if the file is removes, skip to the next file
if(removed_file !== '' && removed_file !== undefined && removed_file == id) self.myupAjax(file,i+1);
else
{
var myupData = new FormData();
myupData.append('upload_file',file[i]);
myupData.append('upload_file_id',id);
myupData.append('max_file_size',this.settings.maxsize);
myupData.append('upload_path',path);
myupData.append('new_name',new_name);
myupData.append('extension',extension);
myupData.append('uploader',this.settings.uploader);
myupData.append('act','upload');
myupData.append('nonce',myup.nonce);
$.ajax(
{
type : 'POST',
url : myup.ajaxurl+'?action=myup-uploads',
data : myupData,
id : id,
fuid : this.fuid,
new_name : new_name,
rawname : rawname,
extension : extension,
path : path,
pathcheck : pathcheck,
removed : removed,
loading : loading,
fixedchars : fixedchars,
cache : false,
contentType : false,
processData : false,
beforeSend : function(xhr, settings)
{
// I added this alert because it shows me that when I'm using the first instance
// after the first file uploads, it starts looking to the file input field
// from the second instance
alert('path: '+settings.path+' pathcheck: '+settings.pathcheck);
// in here I do a bunch of security stuff before uploading
},
xhr: function()
{
// my progress bar function here
},
success : function(response)
{
setTimeout(function()
{
if(response.indexOf(id) != -1)
{
// do success stuff, like green checkmark, remove table row, etc.
}
else
{
// do failure stuff, like red x and error message
}
// AND HERE IS THE IMPORTANT PART
// THIS SAYS TO GO ON TO THE NEXT FILE IN THE ARRAY
// BUT WHEN USING THE FIRST INSTANCE
// IT SENDS US TO THE SECOND INSTANCE'S FILE READER
// if I'm uploading with the second form it's fine
if(i+1 < file.length) self.myupAjax(file,i+1);
},500);
}
});
}
}
}
this.starter();
}
window.MyUp = MyUp;
window.myupRemove = myupRemove;
});
Note the comment block toward the end of the above code snippet, where the comment is in all caps. That's where it completes the ajax upload for a file, then sends us back to do the next one.
So, basically, to reiterate, if I have two forms on the page, when I use the second form, everything works fine. When I use the first form, the first file will upload fine, but then it starts looking for the next file in the input field from the second instance.
Is there a relatively simple solution for this?
In the posted code, the constructor function declares all prototype methods. This causes them to be overridden each time a new MyUp object is created, and they will use the configuration from the last one.
function MyUp(config) {
/// ...
var self = this;
MyUp.prototype.foo = function() {
// use `self`
};
}
Instead, you should declare the methods once and use the this reference to obtain any attached objects:
function MyUp(config) {
/// ...
}
MyUp.prototype.foo = function() {
// use `this`
};
If you need static members for the class (methods or variables that are not attached to any instance), you can declare them as fields of the function, if they are to be used publicly - MyUp.begin = function() {}. Or inside the module, if they are private:
(function() {
var uploadsInProgress = 0;
// declare MyUp and use uploadsInProgress; it will be hidden from customer code
window.MyUp = MyUp;
})();
I am not completely sure if this will resolve the upload issues, but it will definitely let you keep your sanity when instantiating multiple objects.
Well I couldn't get it to work the way Alex Gyoshev suggested (deficiency on my part no doubt), so I decided to get rid of the object/prototype route altogether. Instead of creating instances in the form, I declare a MyUpConfig variable in the global space, as an empty array. Then in each html form, I add MyUpConfig['.$uid.'] = and then my array of settings.
Then in the js file I bind each form's file input and submit events to the unique id, and store each input field's file data in an array like this: TheFiles[uid] = files. So when the upload submit occurs, it gets the uid from the upload button element, and only attempts to upload the files stored in the array matching that unique id.
I now have it working with multiple upload forms on the same page. They can each be running simultaneously without interference.
Related
Automatically Filtering Items By Vendor During Creation of a Record
I have a set of scripts that I'm using that interact with each other. I use a client, user event and suitelet script to create a button that, when pressed, opens a popup with a list of items filtered by vendor. It works fine when I'm in edit however when I use it while creating a record problems arise. Since the record to be created has no vendor or id I can't retrieve an item by vendor. What I'm trying to do is to have the Suitelet retrieve the info from the vendor field that is entered prior to it being saved. Therefore I can filter all the items by vendor and add the necessary items in one go. Is this possible? Am I able to access the info before it is submitted. Below are the Client and Suitelet. The User Event is just a call to the suitelet so for the sake of brevity I left it out. Client Script function addItemButtonCallback(data){ nlapiSelectNewLineItem('item'); nlapiSetCurrentLineItemValue('item', 'item', data); nlapiCommitLineItem('inventoryitem'); } function addItemButton() { var id = nlapiGetFieldValue('id'); if (id != "") { var url = nlapiResolveURL('SUITELET', 'customscript_val', 'customdeploy1') + '&poId='+id; window.open(url, '_blank', 'width=500,height=500'); } } Suitelet function suitelet(request, response){ if(request.getMethod() == 'GET') { var form = nlapiCreateForm('Add Item'); form.addSubmitButton('Submit'); var itemfield = form.addField('custpage_val', 'select', 'Item'); var id = request.getParameter('id'); var rec = nlapiLoadRecord('purchaseorder', id); var vend = rec.getFieldValue('entity'); var search = nlapiSearchRecord(...search parameters...); for (result in search){ if (search[result].getValue('vendor') == vend){ itemfield.addSelectOption(search[result].id, nlapiLookupField('inventoryitem', search[result].id, 'itemid')); } } response.writePage(form); } else { var data = request.getParameter('custpage_item'); response.write('<html><body><script>window.opener.addItemButtonCallback("'+data+'"); window.close();</script></body></html>'); } }
Use nlapiGetFieldValue('entity') on the clientscript and pass it to the Suitelet using a query parameter just like you are doing with poId (if you do this you might not even need poId after all + no need to load the record on the suitelet). Also, you might want to optimize your code by running one search passing an array of itemids instead of calling nlapiLookupField for each item. You might need to modify your beforeLoad so the entity is inserted dynamically when the button is pressed (I cant remember if clientscript button does this) . Something like this: var suiteletURL = nlapiResolveURL('SUITELET', 'customscript_val', 'customdeploy1'); var script = "var entity = nlapiGetFieldValue('entity'); var url = '" + suiteletURL + "'&entityId=' + entity;window.open(url, '_blank', 'width=500,height=500')"; var button = form.addButton('custpage_addItemButton', 'Add Item', script);
ContentTools - How can I pass additional data from a DIV to the payload object, to be passed into the POST array?
I use ContentTools for my content editor/PHP CMS. I'm trying to pass additional values from a "editable div" to the POST array (then it will be stored in a database). The script uses Javascript to get the data and to make the call to my server side code. Relevant JS code for the saving process: // Collect the contents of each editable region into a FormData instance payload = new FormData(); //payload.append('__page__', window.location.pathname); payload.append('page_id', page_id); // Page ID from the Meta Property for (name in regions) { payload.append(name, regions[name]); //payload.append('template', 'template'); } // Send the updated content to the server to be saved onStateChange = function(ev) { // Check if the request is finished if (ev.target.readyState == 4) { editor.busy(false); if (ev.target.status == '200') { // Save was successful, notify the user with a flash if (!passive) { new ContentTools.FlashUI('ok'); } } else { // Save failed, notify the user with a flash new ContentTools.FlashUI('no'); } } }; xhr = new XMLHttpRequest(); xhr.addEventListener('readystatechange', onStateChange); xhr.open('POST', 'update-page.php'); // Server side php file, which will catch the $_POST array. xhr.send(payload); Below you see an example editable div which will be in the POST array when page is saved after editing. Note that the div has additional custom html tags 'data-template'. <div id="content_4" class="content" data-template="5" data-editable data-name="1"> This is some example website text. This is some other example website text. </div> I'm trying to pass along the values from "data-template". What I've tried so far does not work: // Added in: editor.addEventListener('saved', function (ev) { var template = document.querySelector("div[data-template]"); // Get Template name from editable div // Or var template = document.getElementsByTagName("[data-template]")[0].getAttribute('[data-template]'); // Added in: the For In Loop for (name in regions) { payload.append(name, regions[name]); payload.append('template', template); // added but does not work } Also, I don't want to use the div ID as value to be passed on. I'm still trying other ways, but my JavaScript knowledge is not (yet!) as strong as my PHP knowledge. Does someone know a solution to this issue? There must be simple solution to get the value from the data-template, passed on to the POST (only the data-template value of the changed content in the div). Right?
You can select the template data for each region by selecting the region's DOM element by it's editable name (e.g data-name): for (var name in regions) { // Select the region DOM element var regionDOM = document.querySelector('[data-name="' + name + '"]'); // Get the `data-template` attribute var tpl = regionDOM.getAttribute('data-template'); // Add the region HTML and template to the payload payload.append(name, regions[name]); payload.append('template_' + name, tpl); } The reason you get no value for for template at all in your code is that you're calling the getAttribute method with the CSS selector and not just the attribute name you want, e.g .getAttribute('[data-template]') should be .getAttribute('data-template'). The other difference in the code I've posted is that the template for each region is saved. If it will be the same template for all regions then you could modify the code to be: for (var name in regions) { // Select the region DOM element var regionDOM = document.querySelector('[data-name="' + name + '"]'); // Get the `data-template` attribute var tpl = regionDOM.getAttribute('data-template'); // Add the region HTML and template to the payload payload.append(name, regions[name]); } // Set the template value for the payload to that of the last region // found. payload.append('template', tpl);
Image OnClick to Javascript function
I am making a registration page that allows you to register an account to a mysql database for my uni project. In this page you can also 'select' your avatar picture. Here is the code below: <u>Select your avatar:</u><br> <?php // open this directory $image_dir = opendir("images/avatars"); // get each entry while( $image = readdir( $image_dir ) ) { $dirArray[] = $image; } // close directory closedir($image_dir); // count elements in array $indexCount = count($dirArray); // loop through the array of files and print them all in a list for($index=0; $index < $indexCount; $index++) { $extension = substr($dirArray[$index], -3); if( $extension == "jpg" || $extension == "gif" ) { //echo("<a href='#'>"); echo("<img id='$index' onClick='SetAvatar($index)' img src='images/avatars/$dirArray[$index]' class='o'> "); //echo("</a>"); } } ?> <script> function SetAvatar(id) { var image = document.getElementById(id); if( CurSelectedImage != null && id != CurSelectedImage ) { var image_to_unselect = document.getElementById(CurSelectedImage); image_to_unselect.Selected = false; image_to_unselect.style.border = null; } if( image.Selected != true ) { image.style.border = 'medium solid blue'; image.Selected = true; SelectedImage = id; } else { image.style.border = null; image.Selected = false; SelectedImage = null; } } </script> This selects the avatar picture, makes the border blue and stores the selected image id in a variable but how would I pass the variable with the selected image id back to php so I can save it?? Thanks
can you show your CSS codes too ? or you can find here jQuery select and unselect image your answer
You have to think about your application design. Mixing PHP and Javascript isn't the best idea. Use a API instead of mixing code. You can call this API with Ajax. I think this is a good design choice: Create a getImages API in PHP: You output the data in a json array. You calling this api with javascript and generating the DOM with the json You creating a click handler in javascript and calling again a API in PHP You getting the json data in PHP and saving it in your db :)
My suggestion would be to use a CSS class. Remove any existing instances of the class then add the class to the selected image. function SetAvatar(id) { //remove existing border(s) a while loop is used since elements is a live node list which causes issues with a traditional for loop var elements = document.getElementsByClassName("selected-avatar"); while (elements.length > 0) { var element = elements.item(0); element.className = element.className.replace(/(?:^|\s)selected-avatar(?!\S)/g , ''); } var image = document.getElementById(id); image.className += " selected-avatar"; } To pass the avatar value, I'd suggest using a form to pass all of your registration data to process_register (if you are not already). You can add an input of type hidden to your form and populate the value through javascript on submit. html: <form id="registration-form" action="process_register.php" method="put"> <input id="registration-avatar" type="hidden" /> <button id="registration-submit">Submit</button> </form> javascript: document.getElementById("registration-submit").onclick = function(){ var avatarValue; //you'll need to write some code to populate the avatarValue based on the selected avatar image document.getElementById("registration-avatar").value = avatarValue; document.getElementById('registration-form').submit(); }; Then in php you can get the values using $_POST http://php.net/manual/en/reserved.variables.post.php
Auto Form Post With Url Function
I have a problem with javascript. I use google api and it contains ajax. The problem here is that, I need to catch values from URL like http://examplesite.com/index.php?s=some+values . I need to search values automatically. I try to do this for along time. However, I couldn't. How can I do this ? This is my submit form: <form id="searchForm" method="post"> <fieldset style="width: 520; height: 68"> <input id="s" type="text" name="s" /> <input type="submit" value="Submit" id="submitButton" /> Here is my javascript codes: $(document).ready(function(){ var config = { siteURL : 'stackoverflow.com', // Change this to your site searchSite : true, type : 'web', append : false, perPage : 8, // A maximum of 8 is allowed by Google page : 0 // The start page } // The small arrow that marks the active search icon: var arrow = $('<span>',{className:'arrow'}).appendTo('ul.icons'); $('ul.icons li').click(function(){ var el = $(this); if(el.hasClass('active')){ // The icon is already active, exit return false; } el.siblings().removeClass('active'); el.addClass('active'); // Move the arrow below this icon arrow.stop().animate({ left : el.position().left, marginLeft : (el.width()/2)-4 }); // Set the search type config.type = el.attr('data-searchType'); $('#more').fadeOut(); }); // Adding the site domain as a label for the first radio button: $('#siteNameLabel').append(' '+config.siteURL); // Marking the Search tutorialzine.com radio as active: $('#searchSite').click(); // Marking the web search icon as active: $('li.web').click(); // Focusing the input text box: $('#s').focus(); $('#searchForm').submit(function(){ googleSearch(); return false; }); $('#searchSite,#searchWeb').change(function(){ // Listening for a click on one of the radio buttons. // config.searchSite is either true or false. config.searchSite = this.id == 'searchSite'; }); function googleSearch(settings){ // If no parameters are supplied to the function, // it takes its defaults from the config object above: settings = $.extend({},config,settings); settings.term = settings.term || $('#s').val(); if(settings.searchSite){ // Using the Google site:example.com to limit the search to a // specific domain: settings.term = 'site:'+settings.siteURL+' '+settings.term; } // URL of Google's AJAX search API var apiURL = 'http://ajax.googleapis.com/ajax/services/search/'+settings.type+'?v=1.0&callback=?'; var resultsDiv = $('#resultsDiv'); $.getJSON(apiURL,{q:settings.term,rsz:settings.perPage,start:settings.page*settings.perPage},function(r){ var results = r.responseData.results; $('#more').remove(); if(results.length){ // If results were returned, add them to a pageContainer div, // after which append them to the #resultsDiv: var pageContainer = $('<div>',{className:'pageContainer'}); for(var i=0;i<results.length;i++){ // Creating a new result object and firing its toString method: pageContainer.append(new result(results[i]) + ''); } if(!settings.append){ // This is executed when running a new search, // instead of clicking on the More button: resultsDiv.empty(); } pageContainer.append('<div class="clear"></div>') .hide().appendTo(resultsDiv) .fadeIn('slow'); var cursor = r.responseData.cursor; // Checking if there are more pages with results, // and deciding whether to show the More button: if( +cursor.estimatedResultCount > (settings.page+1)*settings.perPage){ $('<div>',{id:'more'}).appendTo(resultsDiv).click(function(){ googleSearch({append:true,page:settings.page+1}); $(this).fadeOut(); }); } } else { // No results were found for this search. resultsDiv.empty(); $('<p>',{className:'notFound',html:'No Results Were Found!'}).hide().appendTo(resultsDiv).fadeIn(); } }); } function result(r){ // This is class definition. Object of this class are created for // each result. The markup is generated by the .toString() method. var arr = []; // GsearchResultClass is passed by the google API switch(r.GsearchResultClass){ case 'GwebSearch': arr = [ '<div class="webResult">', '<h2>',r.title,'</h2>', '<p>',r.content,'</p>', '',r.visibleUrl,'', '</div>' ]; } // The toString method. this.toString = function(){ return arr.join(''); } } });
Look at my answer here. As you can see, it is not too difficult to set a get parameter. Now, I will show you how you can get a get parameter: function getGetParameter(paramName) { var url = window.location.href; if (url.indexOf(paramName + "=") >= 0) { var returnValue = url.substring(url.indexOf(paramName + "=")); if (returnValue.indexOf("&") >= 0) { returnValue = returnValue.substring(0, returnValue.indexOf("&")); } return returnValue.substring(returnValue.indexOf("=") + 1); } return null; } As about searching for values automatically, you need to specify what and how would you like to search for, as this can be needed/done literally in infinitely many ways.
maybe this is the problem: you're trying to use an API and it's no longer avaiable. Object {responseData: null, responseDetails: "This API is no longer available.", responseStatus: 403} More information here: https://developers.google.com/image-search/v1/jsondevguide Now, I'm trying to find a migration to version 2.
sql.js GUI example - Force a specific database instead of select one
I'm trying to use SQL.JS in order to build a simple local SQLite database browser without any server interaction. I'm using the GUI example page to test. The HTML GUI example page uses <input type='file' id='dbfile'> in order to allow the user to select the database file, then the HTML page calls GUI.JS like this: var dbFileElm = document.getElementById('dbfile'); // Load a db from a file dbFileElm.onchange = function() { var f = dbFileElm.files[0]; var r = new FileReader(); r.onload = function() { worker.onmessage = function () { toc("Loading database from file"); // Show the schema of the loaded database editor.setValue("SELECT `name`, `sql`\n FROM `sqlite_master`\n WHERE type='table';"); execEditorContents(); }; tic(); try { worker.postMessage({action:'open',buffer:r.result}, [r.result]); } catch(exception) { worker.postMessage({action:'open',buffer:r.result}); } } r.readAsArrayBuffer(f); } And it's working fine. Now I would like to force a specific database name and location. I try to use : <input type='text' value='<MY_DB_FILE>' id='dbfile'> (where MY_DB_FILE is the name of my DB file located in the same folder as the HTML page). I also change dbFileElm.onchange = function() into dbFileElm.onload = function() But nothing works and the ID dbfile doesn't seem to contain any usable data and the function is not called.