nesting <button> inside <form> causes unexpected behavior - php

I'm using ZURB Foundation 6.4 (ZURB template) for my Website.
I wanted to test out my newly implemented backend and tried to gather some input and send it to my php backend via jquery AJAX.
Meanwhile, I've managed to do so, but I encountered a very strange problem.
I've used the following building block:
https://foundation.zurb.com/building-blocks/blocks/floated-label-wrapper.html
I modified it a little, but just concerning the id's and placeholders and such stuff, nothing functional.
In the end, I had this markup used as a partial for one of the views I've generated:
<form class="callout text-center">
<h2>Become A Member</h2>
<div class="floated-label-wrapper">
<label for="full-name">Forename</label>
<input type="text" id="forenameInput" name="forename input" placeholder="forename">
</div>
<div class="floated-label-wrapper">
<label for="email">Surname</label>
<input type="text" id="surnameInput" name="surname input" placeholder="surname">
</div>
<div class="floated-label-wrapper">
<label for="pass">Email</label>
<input type="email" id="emailInput" name="email input" placeholder="email">
</div>
<button class="button expanded" id="submitUserDataButton">Sign up</button>
</form>
The button at the very end was once an input with type submit, I've changed that to a button since it suited my needs better.
However, the behavior, both with the input and the button, was always the same as long as the button/input was nested inside the form element:
After clicking it, the site would reload and the called function would execute until it hit my ajax.
Now for completeness, I'll post the AJAX here (it was wrapped intp/called by another function but this doesnt matter here):
function sendUserDataToBackend(userDataInputCollection){
console.log("sendUserDataToBackend was entered")
return $.post("http://localhost:8099/test2.php"
}).then((response) => {
console.log(response)
})
}
It entered the function and the console.log happened and then...nothing. The AJAX itself never executed.
I couldn't really find out why that is, I just figured out how to circumvent it.
I just put my button outside the form element and everything worked fine.
Now, why is that?
Why does having the button nested inside the form element cause such trouble, like causing a page reload and then even preventing an AJAX call from happening?
I mean, forms are made for taking input and sending it to the backend, aren't they? Or have they "gotten old" in some way and one should avoid using them?
How do these elements work, what are their "side effects"?
EDIT:
Here is the handler Code as requested
The logic for the handler is exported from file A
export async function executeRegistration(){
let userDataInputCollection = getUserDataInput()
userDataInputCollection = JSON.stringify(userDataInputCollection)
console.log(userDataInputCollection)
await sendUserDataToBackend(userDataInputCollection)
}
function getUserDataInput(){
let userDataForename = $('#forenameInput').val()
let userDataSurname = $('#surnameInput').val()
let userDataMail = $('#emailInput').val()
let userDataInputCollection = {
forename : userDataForename,
surname : userDataSurname,
email : userDataMail
}
return userDataInputCollection
}
function sendUserDataToBackend(userDataInputCollection){
console.log("sendUserDataToBackend was entered")
return $.post("http://localhost:8099/test2.php", {
userDataInputCollection : userDataInputCollection
}).then((response) => {
console.log(response)
})
}
And imported to file B, where it is attached via jquery:
import * as registrationJS from "./lib/registrationLogic.js"
$('#submitUserDataButton').on('click', function(){
registrationJS.executeRegistration()
})

Clicking a submit button will submit the form. That's the point of submit buttons!.
The browser will leave the page (and load the new page). JavaScript running in the old page will be cancelled (because JS runs in the page, leaving the page quits the program).
If you want to use Ajax instead of regular form submission, then you need to prevent the regular form submission.
Note that best practice is also to bind to the form's submit event and not the button's click event. This better captures form submissions triggered without using the button.
Replace:
$('#submitUserDataButton').on('click', function(){
registrationJS.executeRegistration()
})
With:
$('form').on("submit", function (event) {
event.preventDefault();
registrationJS.executeRegistration();
});

Related

Recaptcha invisible never sends form name in post [duplicate]

Ok, this is less of a question than it is just for my information (because I can think of about 4 different work arounds that will make it work. But I have a form (nothing too special) but the submit button has a specific value associated with it.
<input type='submit' name='submitDocUpdate' value='Save'/>
And when the form gets submitted I check for that name.
if(isset($_POST['submitDocUpdate'])){ //do stuff
However, there is one time when I'm trying to submit the form via Javascript, rather than the submit button.
document.getElementById("myForm").submit();
Which is working fine, except 1 problem. When I look at the $_POST values that are submitted via the javascript method, it is not including the submitDocUpdate. I get all the other values of the form, but not the submit button value.
Like I said, I can think of a few ways to work around it (using a hidden variable, check isset on another form variable, etc) but I'm just wondering if this is the correct behavior of submit() because it seems less-intuitive to me. Thanks in advance.
Yes, that is the correct behavior of HTMLFormElement.submit()
The reason your submit button value isn't sent is because HTML forms are designed so that they send the value of the submit button that was clicked (or otherwise activated). This allows for multiple submit buttons per form, such as a scenario where you'd want both "Preview" and a "Save" action.
Since you are programmatically submitting the form, there is no explicit user action on an individual submit button so nothing is sent.
Using a version of jQuery 1.0 or greater:
$('input[type="submit"]').click();
I actually was working through the same problem when I stumbled upon this post. click() without any arguments fires a click event on whatever elements you select: http://api.jquery.com/click/
Why not use the following instead?
<input type="hidden" name="submitDocUpdate" value="Save" />
Understanding the behavior is good, but here's an answer with some code that solved my problem in jquery and php, that others could adapt. In reality this is stripped out of a more complex system that shows a bootstrap modal confirm when clicking the delete button.
TL;DR Have an input dressed up like a button. Upon click change it to a hidden input.
html
<input
id="delete"
name="delete"
type="button"
class="btn btn-danger"
data-confirm="Are you sure you want to delete?"
value="Delete"></input>
jquery
$('#delete').click(function(ev) {
button.attr('type', 'hidden');
$('#form1').submit();
return false;
});
php
if(isset($_POST["delete"])){
$result = $foo->Delete();
}
The submit button value is submitted when the user clicks the button. Calling form.submit() is not clicking the button. You may have multiple submit buttons, and the form.submit() function has no way of knowing which one you want to send to the server.
Here is another solution, with swal confirmation. I use data-* attribute to control form should be send after button click:
<button type="submit" id="someActionBtn" name="formAction" data-confirmed="false" value="formActionValue">Some label</button>
$("#someActionBtn").on('click', function(e){
if($("#someActionBtn").data("confirmed") == false){
e.preventDefault();
swal({
title: "Some title",
html: "Wanna do this?",
type: "info",
showCancelButton: true
}).then(function (isConfirm) {
if (isConfirm.value) {
$("#someActionBtn").data("confirmed", true);
$("#someActionBtn").click();
}
});
}
});
i know this question is old but i think i have something to add... i went through the same problem and i think i found a simple, light and fast solution that i want to share with you
<form onsubmit='realSubmit(this);return false;'>
<input name='newName'/>
<button value='newFile'/>
<button value='newDir'/>
</form>
<script>
function getResponse(msg){
alert(msg);
}
function realSubmit(myForm){
var data = new FormData(myForm);
data.append('fsCmd', document.activeElement.value);
var xhr = new XMLHttpRequest();
xhr.onload=function(){getResponse(this.responseText);};
xhr.open('POST', 'create.php');
// maybe send() detects urlencoded strings and setRequestHeader() could be omitted
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send(new URLSearchParams(data));
// will send some post like "newName=myFile&fsCmd=newFile"
}
</script>
summarizing...
the functions in onsubmit form event are triggered before the actual form submission, so if your function submits the form early, then next you must return false to avoid the form be submitted again when back
in a form, you can have many <input> or <button> of type="submit" with different name/value pairs (even same name)... which is used to submit the form (i.e. clicked) is which will be included in submission
as forms submitted throught AJAX are actually sent after a function and not after clicking a submit button directly, they are not included in the form because i think if you have many buttons the form doesn't know which to include, and including a not pressed button doesn't make sense... so for ajax you have to include clicked submit button another way
with post method, send() can take a body as urlencoded string, key/value array, FormData or other "BodyInit" instance object, you can copy the actual form data with new FormData(myForm)
FormData objects are manipulable, i used this to include the "submit" button used to send the form (i.e. the last focused element)
send() encodes FormData objects as "multipart/form-data" (chunked), there was nothing i could do to convert to urlencode format... the only way i found without write a function to iterate formdata and fill a string, is to convert again to URLSearchParams with new URLSearchParams(myFormData), they are also "BodyInit" objects but return encoded as "application/x-www-form-urlencoded"
references:
https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send
https://developer.mozilla.org/en-US/docs/Web/API/FormData
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams
https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/requestSubmit#usage_notes (proves that form.submit() does not emulate a submit button click)
Although the acepted answer is technicaly right. There is a way to carry the value you'd like to assign. In fact when the from is submited to the server the value of the submit button is associated to the name you gave the submit button. That's how Marcin trick is working and there is multiple way you can achive that depending what you use. Ex. in jQuery you could pass
data: {
submitDocUpdate = "MyValue"
}
in MVC I would use:
#using (Html.BeginForm("ExternalLogin", "Account", new { submitDocUpdate = "MyValue" }))
This is actually how I complied with steam requirement of using thier own image as login link using oAuth:
#using (Html.BeginForm("ExternalLogin", "Account", new { provider = "Steam" }, FormMethod.Post, new { id = "steamLogin" }))
{
<a id="loginLink" class="steam-login-button" href="javascript:document.getElementById('steamLogin').submit()"><img alt="Sign in through Steam" src="https://steamcommunity-a.akamaihd.net/public/images/signinthroughsteam/sits_01.png"/></a>
}
Here is an idea that works fine in all browsers without any external library.
HTML Code
<form id="form1" method="post" >
...........Form elements...............
<input type='button' value='Save' onclick="manualSubmission('form1', 'name_of_button', 'value_of_button')" />
</form>
Java Script
Put this code just before closing of body tag
<script type="text/javascript">
function manualSubmission(f1, n1, v1){
var form_f = document.getElementById(f1);
var fld_n = document.createElement("input");
fld_n.setAttribute("type", "hidden");
fld_n.setAttribute("name", n1);
fld_n.setAttribute("value", v1);
form_f.appendChild(fld_n);
form_f.submit();
}
</script>
PHP Code
<?php if(isset($_POST['name_of_button'])){
// Do what you want to do.
}
?>
Note: Please do not name the button "submit" as it may cause browser incompatibility.

Stop page refreshing when pressing HTML button?

Hello guys I'm new to internet languages and I would like your help explained with apples!
I'm trying to make a webserver controlled robot with a raspberry pi 3b+. I already got that working with some HTML calling some PHP code and then executing Python scripts in order to move the robot. The thing is, when I press a button to move the robot the page refreshes then loads everything again making it really annoying. (HTML and PHP are in the same document)
I've read some post where people say to use <button> tags with type="button", but when I do that nothing happens. Let me share with you the code. Other people say to use AJAX, but I don't really know how to.
HTML:
<form action="" method="post">
<div>
<div>
<button type="button" name="boton7"><img src="imagenes/up.png"></button>
</div>
<div>
<button type="button" name="boton8"><img src="imagenes/left.png"></button><!--
--><button type="button" name="boton10"><img src="imagenes/stop.png"></button><!--
--><button type="button" name="boton9"><img src="imagenes/right.png"></button><!--
-->
</div>
<div>
<button type="button" name="boton6"><img src="imagenes/down.png"></button>
</div>
</div>
</form>
PHP:
<?php
//Primera fila || mover_arriba.py
if(isset($_POST['boton6'])){
exec('python /var/www/html/mover_arriba.py');
}
//Primera fila || mover_abajo.py
if(isset($_POST['boton7'])){
exec('python /var/www/html/mover_abajo.py');
}
?>
I would like to know if it can done without using AJAX or JS (interpreted languages are confusing to me) or if I can modify something on this code to achieve what I want. As you can see I used a form, I don't really understand if a button can do something without a form, why sometimes people use input="submit", I've also seen "onclick=". Please use as clear as possible answers.
If you need anything else please let me know!
EDIT: I forgot to mention that if I remove type="button" from this <button type="button" it works.
The bad news is that you will have to use JavaScript and AJAX to accomplish this. There's simply no (reasonable) way around it.
The good news is that what you want to do is actually quite simple. Since there is no conditional data and no return data to handle, the bar is already pretty low. I also assume that you are not worried about bad actors abusing vulnerabilities in your code, so let's dive in.
First off, let's get a library that can do AJAX calls. While not necessary, this makes everything a lot easier.
Inside your <head> element, put the following line:
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
Next, add an ID to your <form> element so it is easier for us to access with jQuery.
<form id="robotform" action="" method="post">
Now let's add some JS below the form to handle the form submissions. It has to be placed after because the html elements need to exist before this code is called. Code below is mostly adapted from the answer to this question: Submitting HTML form using Jquery AJAX
<script type='text/javascript'>
/* Get the name of the button that was pressed */
var buttonpressed;
$('button').click(function() {
buttonpressed = $(this).attr('name');
})
/* attach a submit handler to the form */
$("#robotform").submit(function(event) {
/* stop form from submitting normally */
event.preventDefault();
/* target url is the current page */
var url = window.location.href;
/* Create the data as a string so the button name is sent properly */
var data = buttonpressed + '=true';
/* Send the data using post with element id name and name2*/
var posting = $.post( url, data );
/* Alerts the results if unsuccessful */
posting.fail(function( xhr, status, error ) {
alert('Error sending the command: ' + error);
});
});
</script>
One possible solution could be that you could have your PHP code return a 'false' value back to the form. This would prevent the page from refreshing.
This way the PHP code will call the python code but the form will not refresh since it has received a false value back from the PHP function.

Wordpress search results in modal

I am complete php/js newbie and i got stuck on something that i cant figure out.
I have page at www.test.com/page with a search form that calls www.test.com/results like this:
<form method="post" action="https://www.test.com/results">
<input type="text" placeholder="Enter URL:" required="">
<button>Search</button>
</form>
Form gets URL that the user typed in, passes it to /results, the line ($url = $_POST['url'];) is where it is analyzed and results are displayed.
But, i would want the search results to open in (bootstrap) modal instead of new page. I know this can be done with AJAX but i am complete newbie and am looking for most dirty simple solution that would make it work.
Again, sorry if this is too "newbie" type of question, i am still learning.
Yes, you can use jQuery and AJAX to control the form submit. So something akin to the code example below should do the trick:
$('#myForm').on('submit', function(event) {
$.post('https://www.test.com/results', { URL: "some_url.com" }, function(data) {
// Render the results onto your modal anyway you want with data
// retrieved from server here
$("#my-modal-object").html(data);
}).error(function() {
// Handle the event when the call to "/results" fails
alert("Yikes! Call to /results failed!");
});
// Prevents default browser behaviour which submits the form
// then routes to another page, if specified
event.preventDefault();
});
Short explanation:
We attached a "submit" event listener to your form object and performed a POST AJAX request to your server endpoint /results. Server passes back the processed search results into the callback function of $.post and renders it onto your modal object. You may also change the 2nd argument of $.post, i.e. { URL: "some_url.com" } to whatever data object you want to pass to your server.
This should help you get started with rendering your search results onto your modal element instead of navigating to a new page.

Ajax sending date data

I have a problem with my jquery script, it is returning error when I try to send the date value from my form, when I leave it in blank, it doesn't show me an error.
<div class="field-wrap">
<input type="date" name="fecha_nacimiento" required autocomplete="off" maxlength="30" placeholder="Fecha de nacimiento">Fecha de nacimiento</input>
</div>
<script>
$(function(){
$('#entrarBt').click(function(){
$.ajax({
url: 'registro_dpb.php',
type: 'POST', // GET or POST
data: $("#miForm").serialize(), // will be in $_POST on PHP side
success: function(data) { // data is the response from your php script
// This function is called if your AJAX query was successful
alert("Response is: " + data);
},
error: function() {
// This callback is called if your AJAX query has failed
alert("Error!");
}
});
});
});
</script>
Your problem was pretty subtile... Making it hard to find.
But the solution is really simple.
You use a <button> inside a <form> which is absolutely correct.
But you have to know that in HTML5, if the type of a <button> is not explicitly defined as "button", its default type is "submit".
Reference here.
This was the issue...
Since you want to submit using an ajax request, which allow to receive a response without reloading the page, you have to "prevent" this normal behavior of a <button>.
The submit made by the button was not sent to your PHP script, but to your HTML page (there was no other action defined in the <form> tag, so the default is "self".
So the page reloads... Making your ajax request to fail.
So there is two ways to fix this:
1: Define the button type as "button":
<button type="button" id="entrarBt" [+ other attributes]>Entrar</button>
or
2: Prevent this default behavior using prevent.default() in you click handler.
$('#entrarBt').click(function(e){
e.preventDefault();
$.ajax({
//...
I think the second one is more evident for another programmer who could review your code, but the first is ok too.
For the benefit of the other SO readers:
We *(me and Javier)* checked almost every other error possibilities [in chat][3].
I finally found the cause when, for a test, I commented out the whole ajax block and then noticed that the page was still submitting.
Fixing this completely resolved the issue.
This is a tricky thing to absolutely know!
In short, a <button> within a HTML5 <form> is a submit by default!

Website design prevents data being posted to server

I have a big problem with my website.
I have made it in a way that seems to stop be from doing anything.
I have a number of containers, the main part of the page has three small containers all on top of each other and then a bigger container next to them that has the main content. The content that is shown in this main container is pulled from other pages so I don't have to refresh the whole page ever time a link is pressed. So I have one main page (the index) and a bunch of other content filled pages.
Now, if a page were to need to post data to the server to process it and then confirm with the user, this can't be done with normal PHP like I'm used to because the whole page is refreshed and it goes back to the default.
So I thought, I know Ajax can do this. I can post data to the server, process it and then change something on that page without loading anything.....
But I was wrong, it seems that it still wants to refresh the whole page meaning I lose my data. Also with the Ajax I am using "post" not "get" but for some reason it's putting the data into the address bar.
Is there a way I can keep my current structure and be able to do this, or am I doomed?
Any help, tips, code or advice would be MORE than welcome and thank you for the time and help.
Oh yeah, if I view the content outside of the index page the script runs just fine, it's only when the index pulls it from another page.
Ajax:
unction pass()
{
// Real Browsers (chrome)
if (window.XMLHttpRequest)
{
xhr = new XMLHttpRequest();
}
// IE
else if (window.ActiveXObject)
{
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
var oldPass = document.getElementById('oldPass').value;
var newPass = document.getElementById('newPass').value;
var newPassCheck = document.getElementById('newPassCheck').value;
xhr.open("POST","changeSettings.php");
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
var obj = {oldPass: oldPass, newPass: newPass, newPassCheck: newPassCheck};
xhr.send("data=" + JSON.stringify(obj));
xhr.onreadystatechange=function()
{
if (xhr.readyState==4)
{
//grade = xhr.responseText;
document.getElementById("myDiv").innerHTML = xhr.responseText;
//document.write.grade;
//alert ("Nice essay. Your grade is " + grade);
}
}
return false;
}
Here is the original page:
<div id="content">
<form>
<h1>This page is still under construction please do not attempt to use it!</h1>
<p>
Old Password: <input type="password" name="oldPass" id="oldPass"><br />
new Password: <input type="password" name="newPass" id="newPass"><br />
Retype Password: <input type="password" name="newPassCheck" id="newPassCheck"><br />
<input type="submit" name="submit" value="Submit" onClick="return pass();">
</p>
</form>
<div id="myDiv" name="myDiv"> </div>
</div>
Just because you're supplying "POST not GET" in the form doesn't mean ajax will handle it this way.
What needs to be actually done is attach to the submit event of the form, then let AJAX handle it the rest of the way. On a confirmed submission (or even a failure) you can update content (or show errors).
To keep it simple with jQuery...
<div id="content-container">
<form method="post" action="/some/submission/page.php">
<!-- flag to let the landing page know it's an ajax request
this is optional, but IMHO it makes for a more seamless
experience -->
<input type="hidden" name="ajax" value="true" />
<!-- controls go here -->
</form>
</div>
So there's your form. Now, you need to attach to the submit event. Again, I use jQuery for simplicity, but feel free to use any method. I also am creating a very generic controller here so you could presumably use it for every form found on the page, but that's up to you. (And, because we still decorate the <form> an absence of javascript will still proceed, but when it IS there, it will use the nice ajax look and feel)
// use .live to catch current and future <form>s
$('form').live('submit',function(){
var target = $(this).prop('action'),
method = $(this).prop('method'),
data = $(this).serialize();
// send the ajax request
$.ajax({
url: target,
type: method,
data: data,
success: function(data){
//proceed with how you want to handle the returned data
}
});
});
The above will take a normal form found on the page and make it submit via AJAX. You may also want to bind to $.ajaxError so you can handle any failures.
Also, depending on the content you return from the AJAX call, you can either pass the entire response back to the container ($('#content-container').html(data); in the success call), or if it's JSON or plain text, display other data.
Oh, and using my example, you may want to have something like the following in your posted page:
<?php
$ajax_call = isset($_POST['ajax']);
if (!$ajax_call){
// not an ajax call, go ahead with your theme and display headers
}
// output content as usual
if (!$ajax_call){
// again, not ajax, so dump footers too
}
(That way when it's AJAX, only the info in your container is returned, otherwise display the page as usual because they probably don't support AJAX/JavaScript).
You need to put up the page or post a code example in order to get answers to this question.
If I were to take a guess, it would be that you are not preventing submission of the form, so it's firing off the ajax request like you asked, but also submitting the form. In order to prevent it, you need to select the submit button and have it return false. Here's a quick example with jquery of how you would do this
$('input[type=submit]').click(function(){
$.ajax({ ... request here ... });
return false
});
or you can also catch the click event and prevent default, as such
$('input[type=submit]').click(function(event){
event.preventDefault();
});
Since I can't see any of your code, this is not guaranteed to be right. If you post the code, I can revise this. In the meantime, hopefully I guessed it!

Categories