I have three forms on a page. They each have multiple inputs including files. I would like so that when I submit the last form, the inputs for all three forms are sent to the POST data for the action location. I can jQuery if necessary.
Here's how you could combine multiple forms into one. Now, a warning: if you have more than one form with file-type inputs, you've got a problem that's really hard to solve. The browser will not let you use XMLHttpRequest (ie Ajax, in any form) to post a multi-part form POST with file inputs. You also won't be able to create a new form with the file inputs in it, because you can't set the value of file input elements with Javascript. Thus, the only way this can work is if you have multiple (3? whatever) forms, and only ONE Of them has file inputs. If that's the case, then what you can do is pull all the (non-file) inputs from the other 2 forms into the other form, and then submit that one.
function whenFormsCollide() {
// pass in one or more form elements
var forms = $.makeArray(arguments);
var hasFiles = 0, targetForm = null;
$.each(forms, function(i, f) {
if ($(f).find('input:file').length > 0) {
++hasFiles;
targetForm = f;
}
});
if (hasFiles > 1) throw "More than one form has 'file' inputs";
targetForm = targetForm || forms[0];
$.each(forms, function(i, f) {
if (f === targetForm) continue;
$(f).find('input, select, textarea')
.appendTo($(targetForm));
});
$(targetForm).submit();
}
I haven't tested that, but I've done stuff like it many times and I know that building up a <form> element works fine, even in IE6. (IE has some weird issues with form fields sometimes, but I think this part should be OK. At worst, instead of just being able to "move" the fields with that "appendTo" call you'd have to copy out the names and values and make new form fields.)
You may want to try using serialize() and append the string to your action URL.
You could submit them to hidden Iframes, that way you maintain control of the host page.
You can write one JS function that submits all three forms.
Your only option right now is a jQuery AJAX request (or a XMLHTTP one, but that's not recommended).
Try rethinking your design, I mean, why do you need 3 forms on one page... that's too `formy' for me already.
There is something else you can probably do: put the jQuery UI dialog box container div inside one form (this should work, I guess) and just have the fields within it...
I used below code to submit two forms' data in my website.
The idea is that you get the multiple forms data using serialize and combine that data and equalize that to data parameter of the $.ajax function.
.
// submits two forms simultaneously
function submit_forms(form1_id, form2_id)
{
var frm1_name = $("#" + form1_id).attr('name');
var frm2_name = $("#" + form2_id).attr('name');
if (frm1_name == frm2_name)
{
alert('The two forms can not have the same name !!');
}
else
{
var frm1_data = $("#" + form1_id).serialize();
var frm2_data = $("#" + form2_id).serialize();
if (frm1_data && frm2_data)
{
$("#div_busy").html('<strong>Processing...</strong><br /><img id="busy" src="./images/progress_bar.gif" border="0" style="display:none;" />');
$("#busy").fadeIn('slow');
$.ajax(
{
type: "POST",
url: "process_sticker_request.php",
data: frm1_data + "&" + frm2_data,
cache: false,
error: function()
{
$("#busy").hide('slow');
$("#div_busy").css({'color':'#ff0000', 'font-weight':'bold'});
$("#div_busy").html('Request Error!!');
},
success: function(response)
{
$("#div_busy").hide('slow');
$("#hdnFormsData").html(response);
// open popup now with retrieved data
window.open('', 'popup2', 'toolbars = 1, resizable=1, scrollbars=1, menubar=1');
document.getElementById("prt").action = 'win_sticker.php';
document.getElementById("prt").target = 'popup2';
document.getElementById("prt").submit();
// reset the action of the form
document.getElementById("prt").action = 'list_preview.php';
}
});
}
else
{
alert('Could not submit the forms !!');
}
}
}
Can you explain the sense of separating information in different forms and combine the information later with JS? And when Java Script is disabled your Formulas didn't work?
Put all together in one form. If you want to evaluate only the special data Fields of your Form, check on the server side which submit button was pressed.
When you have a problem an you need JS to fix a normal communication problem, then you have a conceptional problem. JS can help you to customize and give a better UI - but this problem is useless.
Related
I'm working on a small proof of concept. The goal is to produce a small javascript widget that clients would be able to drop into their site. This widget should detect all forms on the page (think name, email phone, etc) and post any submissions to our API before returning control to the form.
I've searched a bit to see if patterns or libraries exist for this and did not come up with many results (if anyone has some to share, thank you)
Considerations:
Won't know what other libraries are running on the site
Won't know if the page has 1 form or 100 forms
Won't know if the form submits with a simple action tag or something more complex
Do want to be as lightweight (vanilla) as possible
The approach that I've been working out so far does something like the following. However, a lot of forms tend to prevent the submit event for their own validation or method of submissions. Is there a better way to do this that would handle a wider set of use-cases?
window.onload = function() {
for(var i=0; i<document.forms.length; i++){
var form = document.forms[i];
form.addEventListener("submit", (e) => { // Hook, but not all forms will use this
e.preventDefault();
const formData = new FormData(form)
console.log(formData.entries()) // Submitted data
fetch('//some-api-url/', {
method: 'POST',
headers: {'Content-Type': 'application/json',},
body: JSON.stringify(formData.entries()),
}); // Send the data to our backend
return true; // Return control back to the original form
});
}
}
I'm trying to create an upload panel like facebook, but I've got a trouble with <input type="file" />.
Here is facebook upload image panel:
My trouble is: if I click add more (like image above), that means the <input type="file" /> will be clicked again. So, the value will be overridden.
After that, if I click submit button, only 1 image can be uploaded.
My jquery code to upload looks like this:
function Upload(evt, id)
{
var file = document.getElementById("file");
var formData = new FormData();
for (i = 0; i < file.files.length; i++) {
formData.append(file.files[i].name, file.files[i]);
}
formData.append("id", id);
$.ajax({
url: "/Home/Upload",
type: "POST",
dataType: "json",
data: formData,
contentType: false,
processData: false,
success: function (data) {
alert('upload successful...');
},
error: function () {
alert('upload failed...');
}
});
}
The first line: var file = document.getElementById("file");. It means: get the latest value of <input type="file" name="file" id="file" /> (no keep the selected file before).
Can you tell me how to get all the selected files? (I don't talk about multiple).
Thank you!
"My trouble is: if I click add more (like image above), that means the will be clicked again. So, the value will be overridden."
Here's the underlying problem with your script:
"You can't set the value of a file picker from a script" so no direct manipulation of form will work
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#File_inputs
You can't manipulate file inputs from javascript in any meaningful way (for obvious security reasons), you can only read them. However, you can manipulate the DOM. What facebook and other multi-part pickers actually do is create and destroy file input elements in order to allow the flows they want, rather than try to bind anything to the file value of the input.
There are a lot of plugins that handle this complexity for you, but it's pretty doable to get it working once you understand the problem you're working around.
further clarification:
yup, it sounds like you're thinking about it right now! just think of file inputs as read-only, and use another variable to store all your values, and any function to deal with showing previews in the dom reads from that rather than binding directly from the file input.
One extra thing I would add in response to But the value can only append, not remove :((, is that you shouldn't store the values in FormData if you might need to remove values. Instead just use a regular object to store all the values you want to add/modify, and then construct the object when the user submits the form. Something along the lines of this:
var myFormDataObject = {}; // can store inputs in this
// watch onchange and add/remove from myFormDataObject
function sendStuff(){
var formData = new FormData();
for (var key in myFormDataObject) {
formData.append(key, myFormDataObject[key]);
}
// then post/put/patch/etc the form
}
I am using a Bootstrap modal to display an ASP.Net MVC5 form, the form is inserted dynamically into a div using a jquery ajax call to the relevant controller and then opened.
I need to intercept the submission of the form so I would like to bind to the submit event of the form in jquery but have so far only been able to bind to the submit event of all forms since the dynamic forms are of course not present when the main view is rendered e.g.
$('form').submit(...)
rather than
$('#serverForm').submit(...)
Whilst this sort of works, it has a problem in that I actually have 3 different dynamic forms in this view which can be shown using modal popups, thus I need to do one of 2 things:
A) (ideally)manage to intercept the submit event for each form.
B) in the global form event handler, identify which form has been submitted.
I have tried every option I can imagine to use option A including adding the binding to the code which pops the modal. all without success.
I am currently trying to go with option B so that I can then decide where to post the form. This does at least get called when a form is submitted but my problem is that I cannot get the id or name of the form which has been submitted and thus have no way of knowing which one it is.
I have the following handler:
<script>
$(function () {
$('form').submit(function(e) {
// this is always null
var id = $(this).attr('id');
$.ajax({
url: '#Url.Action("EditServer", "AccountAdmin")',
data: new FormData(this),
...
});
});
});
</script>
Within this handler I have tried the following (plus a few more!) to get the form's id:
this.id
$(this).id
$(this).attr('id');
$(this).prop('id');
I have tried adding the handler after the ajax call to populate the modal like this:
$(".server-link").click(function (event) {
event.preventDefault();
$.ajax({
url: $(this).attr("href"),
cache: false,
type: "GET",
dataType: "html",
success: function (data, textStatus, XMLHttpRequest) {
$('#serverDiv').html(data);
$('#serverModal').modal('show');
$('form').submit(function (e) {
var id = $(this).attr(id);
// test to see if handler called
alert(id);
});
},
error: function (jgXHR, textStatus, errorThrown) {
//The commented out message is full of Html but includes compilation errors etc from the server
//alert('An error occured: ' + jgXHR.responseText);
alert(textStatus + ':' + errorThrown);
}
});
});
It's driving me bonkers! I have tried every combination of ideas from various posts with no joy. I need to post using FormData (in one case at least) because there is a file upload (an image) involved. Any assistance is much appreciated.
The problem is that your JavaScript code is running before the form has actually been added to the page. When using AJAX, you need to run whatever JavaScript you need in the callback:
$.get('/some/url', function (result) {
$('#whatever').html(result);
$('form').submit(function(e) {
var id = $(this).prop('id');
// do whatever with id
});
});
Use this instead:
var id = $(e.target).attr('id');
Problem:
I've got 2 drop downs, both populated by information from a database and dependent on some initial information (a json array created in php). The second drop down is also dependent on what was selected in the first dropdown. Once the second dropdown has been selected, the users selections are saved in another database table. If the user leaves and then comes back, I want to be able to reset the drop downs to what they previously selected (but still let them change their selections).
Context:
I have some code that looks like the following:
function eventHandler2(event) {
$.ajax({
url: "someotherurl.php",
data: event.data["context"],
success: function(data) {
// Do some stuff
}
});
}
function eventHandler1(event) {
event.data["context"][$(event.target).id()] = $(event.target).val();
$.ajax({
url: "someurl.php",
data: event.data["context"],
success: function(data) {
$("#element").append(build_input("input2", data));
$("#element input2").change({"context": event.data["context"]}, eventHandler2);
}
});
}
$(document).ready(function() {
var context = // php generated json array.
$("#element").append(build_input("input1", context));
$("#element input1").change({"context": context}, eventHandler1);
});
context includes some data that has to be initialized outside of the event handler and is added to durring events, and build_input just returns an html string of a form input element built with options determined by data or someData. At times the entire html element that includes eventHandler1 (and eventHandler2) will be removed and reinitialized.
My issue is that I want to initialize the two form inputs (built using build_input) with some default values pulled from a database, but once those values have been set I don't want any reinitialization or event handling to use those initial values (which makes adding them to the context object difficult since that object will be used when binding the event handlers).
I would like to set the value for the inputs and then call a change event to simulate a user selecting those values, but because the input elements are built using ajax data, those change events are being getting called before the ajax request have returned and built the input elements.
I could solve this with timeouts, but because the the javascript might run slower on different machines and the ajax calls could take longer than normal, I don't plan on doing it that way. Still, ideally I would like something like this:
$("#element .input1 option[value='" + initial_value + "']").attr('selected', true);
$("#element .input1").change();
to be called when the page loads but only after the elements have been built and bound.
Question:
Is there any way to trigger change events (simulating the user selecting options) only when the page is first loaded and only after the ajax request to build the html input elements have returned?
Is there any way to trigger change events (simulating the user selecting options) only when the
page is first loaded
and only
after the ajax request
to build the html input elements have returned?
These are two separate events. If you need to ensure both events have ocurred use <body onload="loadedBody=true"> and take advantage of the success: attribute of the $.ajax function like this:
function eventHandler1(event) {
event.data["context"][$(event.target).id()] = $(event.target).val();
$.ajax({
url: "someurl.php",
data: event.data["context"],
success: function(data) {
$("#element").append(build_input("input2", data));
$("#element input2").change({"context": event.data["context"]}, eventHandler2);
ajaxComplete();
}
});
}
var ajaxCompleted;
function ajaxComplete() {
if((loadedBody == true) && (ajaxCompleted == false)) {
$("#element .input1 option[value='" + initial_value + "']").attr('selected', true);
$("#element .input1").change();
} else {
setTimeout('ajaxComplete()', 100);
}
}
Don't worry about the setTimeout. It will rarely be used because the page will likely have loaded before the AJAX result arrives.
I've been building an application with PHP/MySQL and JavaScript with Prototype/Scriptaculous.
A page has a search contacts field, with a default set of data in an HTML table. A user types in some characters, and the table get updated.
What's actually happening is the table is getting replaced with a new table and new data.
I've got a JavaScript that works against that table, which is loaded in the standard fashion via script tags at the bottom of the page.
Problem is, it only works on the default data (the part that's loaded with the page), when the search updates the table data, the script stops working. The search still will work since that was originally loaded with the page but it seems my script is unaware of page updates or new data.
How can I get this to work? Do I have to include the script with every Ajax call?
Thanks
Rich
Posting the relevant code would help, but you have most likely attached an event listener to an element that is replaced by the AJAX call.
If that is the case, you will need to recreate and reattach the event handler to the new element, even if that new element is exactly equivalent to the element it is replacing.
OK, I'll post a bit of code here.
But yes an event listener is attached to an element.
Here's a bit of the JavaScript class I was building which looks for events from a search field, collects data from that field and other form elements and sets them up in this.params.
After the data is returned to the AJAX object, it's updated to the page, which is identical to the original code (different rows).
var Compass_Search = Class.create({ ...
search: function() {
$('search_form').observe('change', this.get_data.bind(this));
},
get_data: function(e) {
var ele = e.target;
var filters = $$('.search_option');
if($(ele).tagName == 'INPUT') {
if($(ele).readAttribute('type') == 'checkbox') {
this.watch_filters(filters);
}
}
if(this.default_text == $('search_box').value) {
this.set_text_value('null');
} else {
this.set_text_value($('search_box').value);
}
new Ajax.Request(this.url, {
method: 'post',
parameters: this.params,
onComplete: function(r) {
result_text = r.responseText;
$('main').update(result_text);
}
});
},
...});