I have a application which you can access here. If you open the application please click on the "Add" button a couple of times. This will add a new row into a table below. In each table row there is an AJAX file uploader.
Now the problem is that if I click on the "Upload" button in any row except the first row, then the uploading only happens in the first row so it is only uploading the first file input only.
Why is it doing this and how can I get it so that when then the user clicks the "Upload" button, the file input within that row of the "Upload" button is uploaded and not the first row being uploaded?
Below is the full code where it appends the file AJAX file uploaded in each table row:
function insertQuestion(form) {
var $tbody = $('#qandatbl > tbody');
var $tr = $("<tr class='optionAndAnswer' align='center'></tr>");
var $image = $("<td class='image'></td>");
var $fileImage = $("<form action='upload.php' method='post' enctype='multipart/form-data' target='upload_target' onsubmit='startUpload();' >" +
"<p id='f1_upload_process' align='center'>Loading...<br/><img src='Images/loader.gif' /><br/></p><p id='f1_upload_form' align='center'><br/><label>" +
"File: <input name='fileImage' type='file' class='fileImage' /></label><br/><label><input type='submit' name='submitBtn' class='sbtn' value='Upload' /></label>" +
"</p> <iframe id='upload_target' name='upload_target' src='#' style='width:0;height:0;border:0px solid #fff;'></iframe></form>");
$image.append($fileImage);
$tr.append($image);
$tbody.append($tr);
}
function startUpload(){
document.getElementById('f1_upload_process').style.visibility = 'visible';
document.getElementById('f1_upload_form').style.visibility = 'hidden';
return true;
}
function stopUpload(success){
var result = '';
if (success == 1){
result = '<span class="msg">The file was uploaded successfully!<\/span><br/><br/>';
}
else {
result = '<span class="emsg">There was an error during file upload!<\/span><br/><br/>';
}
document.getElementById('f1_upload_process').style.visibility = 'hidden';
document.getElementById('f1_upload_form').innerHTML = result + '<label>File: <input name="fileImage" type="file"/><\/label><label><input type="submit" name="submitBtn" class="sbtn" value="Upload" /><\/label>';
document.getElementById('f1_upload_form').style.visibility = 'visible';
return true;
}
UPDATE:
Current Code:
var $fileImage = $("<form action='upload.php' method='post' enctype='multipart/form-data' target='upload_target' onsubmit='startUpload(this);' >" +
"<p class='f1_upload_process' align='center'>Loading...<br/><img src='Images/loader.gif' /><br/></p><p class='f1_upload_form' align='center'><br/><label>" +
"File: <input name='fileImage' type='file' class='fileImage' /></label><br/><label><input type='submit' name='submitBtn' class='sbtn' value='Upload' /></label>" +
"</p> <iframe class='upload_target' name='upload_target' src='#' style='wclassth:0;height:0;border:0px solclass #fff;'></iframe></form>");
function stopUpload(success, source_form){
var result = '';
if (success == 1){
result = '<span class="msg">The file was uploaded successfully!<\/span><br/><br/>';
}
else {
result = '<span class="emsg">There was an error during file upload!<\/span><br/><br/>';
}
$(source_form).find('.f1_upload_process').style.visibility = 'hidden';
$(source_form).find('.f1_upload_form').innerHTML = result + '<label>File: <input name="fileImage" type="file"/><\/label><label><input type="submit" name="submitBtn" class="sbtn" value="Upload" /><\/label>';
$(source_form).find('.f1_upload_form').style.visibility = 'visible';
return true;
}
Why am I getting an error on this line below:
$(source_form).find('.f1_upload_form').style.visibility = 'visible';
Without seeing the full cose, your problem seems to be that you are working with ID's, which must be unique within one document. If several elements are using the same ID, in the best case a browser will use the first one (which it does here), in the worst case nothing will work.
When adding a new upload form, you have to give the elements in it unique ID's. You could do that simply by attaching a counting variable to window, e.g.
$(document).ready( function(){ window.formCount=0; } );
You could then add that number to the ID of the newly added form.
Apart from this, by using the this variable, you can carry a reference to the correct form through, e.g. like onsubmit='startUpload(this);' as well as function startUpload(f){...
You should then be able to access things within the form using $(f).find(...).
There are many ways to make this work and solve the issue of multiple ID's. What I would do: var $fileImage = $("<form action... In this form where it says id I would instead use class. Then as above, change the onsubmit (in the same line) by adding "this" to its brackets. Then change the function startUpload as here:
function startUpload(source_form){
$(source_form).find('.f1_upload_process').css('visibility','visible');
$(source_form).find('.f1_upload_form').css('visibility','hidden');
return true;
}
You have to do the same thing for other functions where you want to access something inside the form that is sending a file. Pass a reference to the form to the function using this in the function call's brackets, then access things inside the form as I showed above.
Related
I have some google script that generates an initial form then gathers a number does a lookup and then is supposed to return a second form (getfamily function). The second form which is dynamically generated returns blank. I can see the formHTML variable with data in the logger, but it comes up blank in the browser. Any suggestions would be appreciated.
var ssID="xxx";
var rows = SpreadsheetApp.openById(ssID).getSheetByName("studentinfo").getDataRange().getValues();
function doGet() {
var html = HtmlService.createTemplateFromFile('index2').evaluate()
.setTitle('Lookup').setSandboxMode(HtmlService.SandboxMode.NATIVE);
return html;
};
function getfamily(form){
Logger.log(form.familyid);
var ssID="xxxx";
var rows = SpreadsheetApp.openById(ssID).getSheetByName("studentinfo").getDataRange().getValues();
var formHTML = "<!DOCTYPE html>";
formHTML +="Hello!";
formHTML += '<form id="students">';
var filteredRows = rows.filter(function(row){
var message="made it";
if (row[0] === form.familyid) {
Logger.log(row[2]);
formHTML+= '<input type="checkbox" name ="students value='+ row[1] + '">'+ row[2] + '<br>';
return row[2];
}
});
formHTML+='<input type="submit" value="CheckIn">';
formHTML+='</form>';
Logger.log(formHTML);
var output = HtmlService.createHtmlOutput(formHTML).setSandboxMode(HtmlService.SandboxMode.NATIVE);
return output;
};
Your input type="checkbox" line is hard to figure out what you want. I presume that you plan in insert this form into an already exist DOM so no need the worrying about other tags just stick it in whatever div you have prepared for it.
function getfamily(form){
var ssID="xxxx";
var rows = SpreadsheetApp.openById(ssID).getSheetByName("studentinfo").getDataRange().getValues();
var formHTML='<form id="students">';
var message="made it";
rows.forEach(function(row){
if (row[0]==form.familyid) {
formHTTML=Utilities.formatString('<input type="checkbox" name="students" value="%s" /><br />',row[2]);//I presume that you want to change the name but I cant tell how you planned to do it.
}
});
formHTML+='<input type="button" value="CheckIn" onClick="proceesForm(this.parentNode);" />';
formHTML+='</form>';
return HtmlService.createHtmlOutput(formHTML);
};
You can use submit if you really must but I find using google.script.run to be a lot easier. We need to see more of what you're doing to provide a complete answer.
I have defined an input of type file and a hidden form below it,
<input type="file" name="attachment0" id="attachment0" custom-on-change="uploadfile" ng-show="attachFile" multiple/>
<form class="hidden" id="myForm" method="post" enctype="multipart/form-data" action="SupportRequest">
</form>
"custom-on-change" is an angular directive that calls the function uploadfile() after choosing files. My javascript looks as shown below
var form = $('#myForm');
var n=0;
$scope.attachFile = true;
$scope.uploadfile = function() {
if(n == 0){
var filein = $('#attachment0');
form.append(filein);
$('#attachment0').test();
}
else
{
if(n==1){
var temp = "attachment0" + '_' + n;
var file_in = $('#'+temp);
form.append(file_in);
$('#'+temp).test();}
}
};
$.fn.test = function() {
return this.each(function(){
n++;
$(this).attr('id', this.id + '_' + n);
$(this).attr('name', this.name + '_' + n);
});
};
Am trying to append files twice to the form myForm. When i choose files second time, even after appending, i see that the previously appended input with id="attachment0" is not present in myForm and the input of id="attachment0_1" is present in the form.
Here am trying to upload multiple files multiple times, that is why am dynamically changing the id of the input in test().
I want both input with id attachment0 and attachment0_1 in myForm.
Does anyone know how this can be fixed? And explain this behavior too.
Change your code from form.append(filein) to form.append($('#attachment0').clone()).
It work then. You should use .clone() method to copy elements .
.append() just moves the element from one place to another but for copying first create the copy of the element using .clone() and then append it to your form
looks like in test function you are replacing id,
$(this).attr('id', this.id + '_' + n);
Would is not be better to use ng-repeat? Something like this:
Controller:
$scope.files = [...] // list of files
$scope.uploadfile = function() {
// So stuff to get the file
$scope.files.push(filein);
};
Html:
<!-- Inside the form -->
<div ng-repeat="file in files">{{file}}</div>
I have to use multiple dropzone areas to upload images. I have used the jQuery append() function to dynamically create the div.
The problem is that the dynamically created dropzone is not initialized and therefore not working.
Just make sure to call the plugin on that newly appended element. The problem is the plugin gets attached to only elements which were present initially.
So, call the plugin once again after you append the element so, it gets attached and works again.
Here is the script i have used to do the same.
I have changed the dynamically created input type text's name field by using the querySelector. The querySelector returns the reference of the elements which have custom attribute i have used data-tagline.
Dropzone.options.myDropzone = {
init: function() {
this.on("addedfile", function(file) {
_ref = file.previewTemplate.querySelector('[data-tagline]');
_ref.name = "This is my New name attribute of element";
})
},
previewTemplate:"<div class=\"dz-preview dz-file-preview\">\n "+
"<div class=\"dz-details\">\n "+
"<div class=\"dz-filename\"><span data-dz-name></span></div>\n "+
"<div class=\"dz-size\" data-dz-size></div>\n "+
"<img data-dz-thumbnail class=\"img-responsive img-thumbnail\" />\n "+
"<input type=\"text\" data-tagline />"+
"</div>\n "+
"<div class=\"dz-progress\">"+
"<span class=\"dz-upload\" data-dz-uploadprogress></span>"+
"</div>\n "+
"<div class=\"dz-success-mark\"><span>✔</span>"+
"</div>\n "+
"<div class=\"dz-error-mark\"><span>✘</span>"+
"</div>\n "+
"<div class=\"dz-error-message\"><span data-dz-errormessage></span>"+
"</div>\n"+
"</div>",
};
<div id="my-dropzone" class="dropzone" action="upload.php"></div>
In your script you need a function to create the form for dropzone, and then execute the function Dropzone.discover()
function add_dropzone() {
const drop_zone = document.createElement("form");
drop_zone.setAttribute("class","dropzone");
drop_zone.setAttribute("action","url_to_upload_files/");
drop_zone.setAttribute("id","my_dropzone");
//find a div where you want to add your dropzone
document.getElementById("div_for_dropzone").appendChild(drop_zone);
// this function will find the class="dropzone" tag and load it.
Dropzone.discover();
}
then in your html you just need to add a div with the id="div_for_dropzone"
dynamically create dz element:
var d='<div id="dzFormDiv">';
d+=' <form ';
d+=' class="dropzone"';
d+=' id="my-awesome-dropzone">';
d+=' <input type="hidden" id="dztoken" name="dztoken"> ';
d+=' <input type="hidden" id="dzt2" name="dzt2"> ';
d+=' </form> ';
d+=' <div id="dsbw">';
d+=' <button id="btnRemoveAlldz">clear</button>';
d+=' </div> ';
d+='</div> ';
append to div somewhere
$("#uploads").prepend(d);
start instance
myAwesomeDropzone = new Dropzone("#my-awesome-dropzone", { url: "../cgi/newUploader.exe"});
add options
Dropzone.options.myAwesomeDropzone = {
init: function () {
var myDropZone = this;
$("#btnRemoveAlldz").click(function () {
myDropZone.removeAllFiles();
}
);
myDropZone.on("complete", function (file) {
if(this.getUploadingFiles().length === 0 && this.getQueuedFiles().length === 0) {
consol.log("completed upload");
}
});
myDropZone.on("sending", function (file) {
// do something before uploading
});
},
error: function(){
// call error handling function
},
success: function(file,r){
// called after EACH successfull upload
file.previewElement.classList.add("dz-success");
if(r.indexOf("ok")>-1){
console.log("success");
}else{
console.log(r);
}
}
};
A bit late to the party but they thought about it. As stated in the usage part of the documentation:
Alternatively you can create dropzones programmaticaly (even on non form elements) by instantiating the Dropzone class
// Dropzone class:
var myDropzone = new Dropzone("div#myId", { url: "/file/post"});
You may have to create an element and set some properties manually.
var form = document.createElement('form');
form.classList.add('dropzone');
form.method = 'post';
form.action = '/file/post';
document.getElementById('parent').appendChild(form);
new Dropzone(form);
Don’t forget to specify an url option if you’re not using a form element, since Dropzone doesn’t know where to post to without an action attribute.
I have a form where you can generate automatically additional form boxes and send them to be handeled at PHP-script. How ever as I am quite lousy with Javascript and I am running in the following problem.
When the form is filled out I can see everything is filled out on the URL, except the the boxes created with JS (every box has unique name!). My guess is that the JS generated field drop out of the form tags, but can not figure out how to fix this. I would appreciate if someone could give me pointers or tell me how to fix this. I shortened the code for clarity (if something got left out please tell me). If someone is wondering why I am not using the form action. It´s because drupal tries to forward the site to wrong place if I do (surprise, not too good with drupal either :D)
<?php
require_once('customer.php');
?>
<script type="text/javascript">
var intTextBox=0;
//FUNCTION TO ADD TEXT BOX ELEMENT
function addElement()
{
intTextBox = intTextBox + 1;
var contentID = document.getElementById('content');
var newTBDiv = document.createElement('div');
newTBDiv.setAttribute('id','strText'+intTextBox);
newTBDiv.innerHTML = "<div class='product'><tr><td>Sku/ID: "+intTextBox+": <input type='text' name='sku_" + intTextBox + "'/></div>";
contentID.appendChild(newTBDiv);
}
function removeElement()
{
if(intTextBox != 0)
{
var contentID = document.getElementById('content');
contentID.removeChild(document.getElementById('strText'+intTextBox));
intTextBox = intTextBox-1;
}
}
</script>
<table>
<form name="activate">
<div class='cu'>
<tr><td>Sku/ID (oma): <input type="text" name="sku"></td>
<td><p><a href="javascript:addElement();" >Add product</a>
<a href="javascript:removeElement();" >Remove product</a></p></td></tr>
<div id="content"></div>
</div>
<tr> <td><input type="submit" value="Submit"></td> </tr>
</form>
Customer.php
<?php
if(isset($_GET["sku_1"]))
{
echo "found it";
}
else
echo "did not find it";
?>
Any help would be much appreciated!
You could dynamically change the url of the form tag to include textbox values:
var textboxes = document.getElementsByTagName("input");
for (var i = 0; i < textboxes.length; i++){
var data = "?";
if (textboxes[i].type == "text") {
data += (data == "?" ? "" : "&") + textboxes[i].name + "=" + textboxes[i].value;
}
}
form.action += data;
I haven't tested this, you might have to dynamically add all elements
[UPDATE]
If you have trouble with the form you can try using an absolute path, if you aren't already.
I have a dynamically generated table which is editable. On clicking any cell in the table I can change its text.
In one column there is an image displayed. When the user clicks on it I change the html for that column to <input type='file'> and trigger a click hence making the user choose a file to upload as the an icon.
In the last column of the table I have a commit button. If the user makes some changes and presses commit I have to pick up the whole row ( some text fields and one file field ) and add all the contents to a form including the file the user chose and send it to a python script to upload it to an s3 server.
My question is: How do I send this form?
I'm currently using script this but it is not working as it is only sending text as request.Files turns out empty at the python(django) script side.
function update(a) {
try {
var button = $(a);
var row = $(button.parent());
var rowcount = button.parent().parent().parent().children().index(button.parent().parent());
var filerow = '';
var formrow = new Array();
var rowkey = new Array('Topic', 'TopicDescription');
var cnt = 0;
var form = $('#dyno_form');
row.siblings().each(function () {
if ($(this).find($('input:file')).length > 0) {
$(this).find($('input:file')).appendTo($(form));
} else if ($(this).find($('img')).length == 0) {
formrow[cnt++] = '<input type="text" value="' + $(this).html() + '" name="' + rowkey[cnt - 1] + '"/>';
}
});
$(form).append(formrow[0]);
$(form).append(formrow[1]);
$(form).submit();
} catch (a) {
alert(a);
}
}
and here is the HTML:
<form id='dyno_form' action='' method="post" style="visibility:hidden">{% csrf_token %}</form>
How do I go about doing this?
When you want to upload a file the form element needs to have the correct enctype attribute and the method must be post.
<form enctype="multipart/form-data" method="post" ...
Otherwise only the values of your inputs will be uploaded.