I'm new to MailChimp and need some help.
With their basic newsletter signup form... you simply embed some prepackaged HTML into your page. However the problem with this is that clicking on submit redirects to a MailChimp page. (I don't want to redirect to MailChimp, I want the user to stay on own website after hitting submit.)
They provide an API and plenty of documentation but just about zero useful examples. The API is supposed to allow me to do a full integration with my site or application. It seems that when I read something in their docs that applies to me, I click the link to get more information and I end up going around in circles. They tell you how to do it but they fail to "show" you how to it.
I can get an API Key, they have tons of documentation, and a whole bunch of wrappers & plugins... PHP, Drupal, Wordpress, etc...
The confusion here regarding their pre-packaged solutions is that I just have a regular static HTML page, it's not Wordpress, PHP, or Drupal... so I just don't know where to start ... I don't even know if I'm supposed to use POST or GET.
I'm not a newbie to API's... I do very well with getting the Google Maps API to do whatever I want. However, Google provides real-world working examples in addition to their detailed documentation which is how I learned it. I just want to see it in action before I can grasp the finer points of the API.
Without any solid examples or tutorials in their online documentation, I'm asking how to create the most basic HTML signup form using their API.
EDITED:
Since posting this answer MailChimp has released version 2 & 3 of their API. Version 3 will be the only supported version starting in 2017. As soon as I have a chance to test it, I will update this answer for API version 3.
MailChimp API v3.0
As per notification at the top of this page, all prior versions of the API will not be supported after 2016.
My solution uses PHP in the background for handling the API, and jQuery to facilitate the Ajax.
1) Download a PHP wrapper that supports API v3.0. As of this writing, there is nothing official listed in the latest MailChimp docs that supports v3.0, but several are listed on GitHub, so I selected this one.
2) Create the following PHP file, store-address.php, using your own API key and list ID, and then place it in the same directory as the wrapper from step one. Remember to follow the documentation for your wrapper, but they all seem fairly similar to this.
<?php // for MailChimp API v3.0
include('MailChimp.php'); // path to API wrapper downloaded from GitHub
use \DrewM\MailChimp\MailChimp;
function storeAddress() {
$key = "xxxxxxxxxxxxxxx-us1";
$list_id = "xxxxxx";
$merge_vars = array(
'FNAME' => $_POST['fname'],
'LNAME' => $_POST['lname']
);
$mc = new MailChimp($key);
// add the email to your list
$result = $mc->post('/lists/'.$list_id.'/members', array(
'email_address' => $_POST['email'],
'merge_fields' => $merge_vars,
'status' => 'pending' // double opt-in
// 'status' => 'subscribed' // single opt-in
)
);
return json_encode($result);
}
// If being called via ajax, run the function, else fail
if ($_POST['ajax']) {
echo storeAddress(); // send the response back through Ajax
} else {
echo 'Method not allowed - please ensure JavaScript is enabled in this browser';
}
3) Create your HTML/CSS/JavaScript(jQuery) form (It is not required to be on a PHP page, and the visitor will never see that PHP is being used in the background.)
The response is in JSON so you'll have to handle it correctly.
Here is what my index.html file looks like:
<form id="signup" action="index.html" method="get">
First Name: <input type="text" name="fname" id="fname" />
Last Name: <input type="text" name="lname" id="lname" />
email Address (required): <input type="email" name="email" id="email" />
<input type="submit" id="SendButton" name="submit" value="Submit" />
</form>
<div id="message"></div>
<script src="jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#signup').submit(function() {
$("#message").html("Adding your email address...");
$.ajax({
url: 'inc/store-address.php', // proper url to your "store-address.php" file
type: 'POST', // <- IMPORTANT
data: $('#signup').serialize() + '&ajax=true',
success: function(msg) {
var message = $.parseJSON(msg),
result = '';
if (message.status === 'pending') { // success
result = 'Success! Please click the confirmation link that will be emailed to you shortly.';
} else { // error
result = 'Error: ' + message.detail;
}
$('#message').html(result); // display the message
}
});
return false;
});
});
</script>
MailChimp API version 1:
(original answer)
After fumbling around for a while, I found a site using the PHP example with jQuery. From that I was able to create a simple HTML page with jQuery containing the basic sign-up form. The PHP files are "hidden" in the background where the user never sees them yet the jQuery can still access & use.
1) Download the PHP 5 jQuery example here... (EDIT: links are dead. However, the only important part is the official API wrapper for PHP which is available HERE.)
http://apidocs.mailchimp.com/downloads/mcapi-simple-subscribe-jquery.zip
If you only have PHP 4, simply download version 1.2 of the MCAPI and replace the corresponding MCAPI.class.php file above.
http://apidocs.mailchimp.com/downloads/mailchimp-api-class-1-2.zip
2) Follow the directions in the Readme file by adding your API key and List ID to the store-address.php file at the proper locations.
3) You may also want to gather your users' name and/or other information. You have to add an array to the store-address.php file using the corresponding Merge Variables.
Here is what my store-address.php file looks like where I also gather the first name, last name, and email type:
<?php
function storeAddress() {
require_once('MCAPI.class.php'); // same directory as store-address.php
// grab an API Key from http://admin.mailchimp.com/account/api/
$api = new MCAPI('123456789-us2');
$merge_vars = Array(
'EMAIL' => $_GET['email'],
'FNAME' => $_GET['fname'],
'LNAME' => $_GET['lname']
);
// grab your List's Unique Id by going to http://admin.mailchimp.com/lists/
// Click the "settings" link for the list - the Unique Id is at the bottom of that page.
$list_id = "123456a";
if ($api->listSubscribe($list_id, $_GET['email'], $merge_vars , $_GET['emailtype'])) {
// It worked!
return 'Success! Check your inbox or spam folder for a message containing a confirmation link.';
} else {
// An error ocurred, return error message
return '<b>Error:</b> ' . $api->errorMessage;
}
}
// If being called via ajax, autorun the function
if($_GET['ajax']) {
echo storeAddress();
}
4) Create your HTML/CSS/jQuery form. It is not required to be on a PHP page.
Here is what my index.html file looks like:
<form id="signup" action="index.html" method="get">
First Name: <input type="text" name="fname" id="fname" />
Last Name: <input type="text" name="lname" id="lname" />
email Address (required): <input type="email" name="email" id="email" />
HTML: <input type="radio" name="emailtype" value="html" checked="checked" />
Text: <input type="radio" name="emailtype" value="text" />
<input type="submit" id="SendButton" name="submit" value="Submit" />
</form>
<div id="message"></div>
<script src="jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#signup').submit(function() {
$("#message").html("Adding your email address...");
$.ajax({
url: 'inc/store-address.php', // proper url to your "store-address.php" file
data: $('#signup').serialize() + '&ajax=true',
success: function(msg) {
$('#message').html(msg);
}
});
return false;
});
});
</script>
Required pieces...
index.html constructed as above or similar. With jQuery, the appearance and options are endless.
store-address.php file downloaded as part of PHP examples on Mailchimp site and modified with your API KEY and LIST ID. You need to add your other optional fields to the array.
MCAPI.class.php file downloaded from Mailchimp site (version 1.3 for PHP 5 or version 1.2 for PHP 4). Place it in the same directory as your store-address.php or you must update the url path within store-address.php so it can find it.
Here is an example using version 2.0 of Mailchimp API together with mailchimp-api (a minimal php abstraction class for dealing with the Mailchimp API).
<?php
include('MailChimp.php');
$MailChimp = new MailChimp('API_KEY');
$result = $MailChimp->call('lists/subscribe', array(
'id' => 'LIST_ID',
'email' => array( 'email' => $_POST['email'] ),
'merge_vars' => array(
'MERGE2' => $_POST['name'] // MERGE name from list settings
// there MERGE fields must be set if required in list settings
),
'double_optin' => false,
'update_existing' => true,
'replace_interests' => false
));
if( $result === false ) {
// response wasn't even json
}
else if( isset($result->status) && $result->status == 'error' ) {
// Error info: $result->status, $result->code, $result->name, $result->error
}
?>
Read more about what you can send with the API call at the MailChimp API Documentation.
Here's another example of using version 2.0 of the Mailchimp API using the Official PHP Wrapper.
The difference between my example and others posted here is that I'm using the subscribe method of the Mailchimp_Lists class, accessible through instantiation of the Mailchimp class (->lists), rather than the generic call method.
$api_key = "MAILCHIMP_API_KEY";
$list_id = "MAILCHIMP_LIST_ID";
require('Mailchimp.php');
$Mailchimp = new Mailchimp($api_key);
$subscriber = $Mailchimp->lists->subscribe($list_id, array('email' => $_POST['email']));
if ( ! empty($subscriber['leid'])) {
// Success
}
Related
I'm trying to use one file input element to upload multiple files to Drive using html form. This seems to work only for one file, although the file picker allows selecting multiple files. Back in the script log viewer, I only see one file captured of the two I uploaded. Is this unsupported, or am I going the wrong way about it?
Code.gs:
function logForm(form) {
Logger.log(JSON.stringify(form));
return true;
}
index.html:
<html>
<form id="uploadTest" enctype="multipart/form-data">
<input type="file" multiple="multiple" name="fileUpload">
<input type="button" id="upload" value="upload"
onclick="google.script.run.logForm(document.getElementById('uploadTest'));">
</form>
</html>
Log view:
{"fileUpload":{"contents":"GIF87a\u0001\u0000\u0001\u0000�
\u0000\u0000��̖��,\u0000\u0000\u0000\u0000\u0001\u0000
\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;",
"type":"image/gif","name":"1x1.gif","length":35}}
The multiple file select in the dialog when you click on the browse button of the file field happens only for the new browsers supporting HTML5. It wont allow multiple select for old browsers. For older browsers the only good solutions are flash or javascript plugins. Here is a good resource for jquery uploaders ( some support multiple files ): http://creativefan.com/10-ajax-jquery-file-uploaders/. Hence my suggestion is use some plugin so that its supported on old as well as the new browsers.
I'm using possibility to send array of files. Just add [] to name atrribute:
<form action="/" enctype="multipart/form-data" method="post">
<input type="file" name="files[]" />
<input type="file" name="files[]" />
// etc.
<input type="submit">
</form>
You will have array of arrays in $_FILES
Array
(
[files] => Array
(
[name] => Array
(
[0] => 1.png
[1] => 2.png
)
[type] => Array
(
[0] => image/png
[1] => image/png
)
[tmp_name] => Array
(
[0] => /tmp/phpDQOZWD
[1] => /tmp/phpCELeSw
)
[error] => Array
(
[0] => 0
[1] => 0
)
[size] => Array
(
[0] => 32209
[1] => 64109
)
)
)
Of course, you you'll have to upload them one by one. Not convenient to a large number of files, but works in all browsers. For example,using jQuery you can add one more input each time last files[] input was changed.
function addOneMoreInput() {
$('input[type=file]').last().change(function() {
$(this).after('<input type="file" name="files[]" />');
$(this).off('change');
addOneMoreInput();
});
}
addOneMoreInput();
How about this sample script?
In this sample, the following flow is run.
Select files at browser.
Upload the files every file.
Save each file in Google Drive.
In this sample script, the file IDs of created files are returned to the console.
When you use this, please copy and paste the Google Apps Script and HTML to the script editor, and run the HTML using the dialog, sidebar and Web Apps.
Code.gs: Google Apps Script
function saveFile(obj) {
var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, obj.fileName);
return DriveApp.createFile(blob).getId();
}
index.html: HTML and Javascript
<input name="file" id="files" type="file" multiple>
<input type='button' value='Upload' onclick='getFiles()'>
<script>
function getFiles() {
const f = document.getElementById('files');
[...f.files].forEach((file, i) => {
const fr = new FileReader();
fr.onload = (e) => {
const data = e.target.result.split(",");
const obj = {fileName: f.files[i].name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
google.script.run.withSuccessHandler((id) => {
console.log(id);
}).saveFile(obj);
}
fr.readAsDataURL(file);
});
}
</script>
Note:
index.html can be run as Web Apps and the side bar and dialog of Google Docs.
In this sample script, the input tag uses the multiple attribute.
I'm trying to use one file input element to upload multiple files to Drive using html form. This seems to work only for one file, although the file picker allows selecting multiple files. Back in the script log viewer, I only see one file captured of the two I uploaded. Is this unsupported, or am I going the wrong way about it?
Code.gs:
function logForm(form) {
Logger.log(JSON.stringify(form));
return true;
}
index.html:
<html>
<form id="uploadTest" enctype="multipart/form-data">
<input type="file" multiple="multiple" name="fileUpload">
<input type="button" id="upload" value="upload"
onclick="google.script.run.logForm(document.getElementById('uploadTest'));">
</form>
</html>
Log view:
{"fileUpload":{"contents":"GIF87a\u0001\u0000\u0001\u0000�
\u0000\u0000��̖��,\u0000\u0000\u0000\u0000\u0001\u0000
\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;",
"type":"image/gif","name":"1x1.gif","length":35}}
The multiple file select in the dialog when you click on the browse button of the file field happens only for the new browsers supporting HTML5. It wont allow multiple select for old browsers. For older browsers the only good solutions are flash or javascript plugins. Here is a good resource for jquery uploaders ( some support multiple files ): http://creativefan.com/10-ajax-jquery-file-uploaders/. Hence my suggestion is use some plugin so that its supported on old as well as the new browsers.
I'm using possibility to send array of files. Just add [] to name atrribute:
<form action="/" enctype="multipart/form-data" method="post">
<input type="file" name="files[]" />
<input type="file" name="files[]" />
// etc.
<input type="submit">
</form>
You will have array of arrays in $_FILES
Array
(
[files] => Array
(
[name] => Array
(
[0] => 1.png
[1] => 2.png
)
[type] => Array
(
[0] => image/png
[1] => image/png
)
[tmp_name] => Array
(
[0] => /tmp/phpDQOZWD
[1] => /tmp/phpCELeSw
)
[error] => Array
(
[0] => 0
[1] => 0
)
[size] => Array
(
[0] => 32209
[1] => 64109
)
)
)
Of course, you you'll have to upload them one by one. Not convenient to a large number of files, but works in all browsers. For example,using jQuery you can add one more input each time last files[] input was changed.
function addOneMoreInput() {
$('input[type=file]').last().change(function() {
$(this).after('<input type="file" name="files[]" />');
$(this).off('change');
addOneMoreInput();
});
}
addOneMoreInput();
How about this sample script?
In this sample, the following flow is run.
Select files at browser.
Upload the files every file.
Save each file in Google Drive.
In this sample script, the file IDs of created files are returned to the console.
When you use this, please copy and paste the Google Apps Script and HTML to the script editor, and run the HTML using the dialog, sidebar and Web Apps.
Code.gs: Google Apps Script
function saveFile(obj) {
var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, obj.fileName);
return DriveApp.createFile(blob).getId();
}
index.html: HTML and Javascript
<input name="file" id="files" type="file" multiple>
<input type='button' value='Upload' onclick='getFiles()'>
<script>
function getFiles() {
const f = document.getElementById('files');
[...f.files].forEach((file, i) => {
const fr = new FileReader();
fr.onload = (e) => {
const data = e.target.result.split(",");
const obj = {fileName: f.files[i].name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
google.script.run.withSuccessHandler((id) => {
console.log(id);
}).saveFile(obj);
}
fr.readAsDataURL(file);
});
}
</script>
Note:
index.html can be run as Web Apps and the side bar and dialog of Google Docs.
In this sample script, the input tag uses the multiple attribute.
Let's say that I have a file (file1.php) with a simple form with the action attribute:
echo'
<form action="foo.php" method="post">
Name: <input type="text" name="username" /><br />
Email: <input type="text" name="email" /><br />
<input type="submit" name="submit" value="Submit me!" />
</form>';
$another_var = $user_id+5;
Let's say the foo.php looks something like this:
$sql ... SELECT user_id, username... WHERE username = $_POST['username']; //or so
echo 'We got the user ID. it is in a variable!';
$user_id = $row['user_id'];
As you see, I need the variable $user_id made in foo.php actually to be used in the main file file1.php.
Is there any way to do this? I though that return $user_id would work but I was wrong :-/
Some notes to have into account:
in file1.php there are two forms: one to upload a file (example above) and another to save all the data into a database (that's the reason I need the variable name).
the example is just that, an example. I'm not really adding 5 to the variable requested, but I don't want to copy and paste 100 lines of code to overwhelm everybody.
the variable is also refreshed with javascript, So I see it there but I don't really know how to assign a javascript variable to a php variable (if possible).
THANKS!!!
Here's how I would do it.
The html:
<form id="form1" action="foo.php" method="post">
<!-- form elements -->
</form>
<form id="form2" action="bar.php" method = "post">
<input type="hidden" name="filename" value="" />
<!-- other form elements -->
</form>
The javascript
$('#form1').submit(function(){
var formdata = ''; //add the form data here
$.ajax({
url: "foo.php",
type: "POST",
data: formdata,
success : function(filename){
//php script returns filename
//we apply this filename as the value for the hidden field in form2
$('#form2 #filename').val(filename);
}
});
});
$('#form2').submit(function(){
//another ajax request to submit the second form
//when you are preparing the data, make sure you include the value of the field 'filename' as well
//the field 'filename' will have the actual filename returned by foo.php by this point
});
The PHP
foo.php
//receive file in foo.php
$filename = uniqid(); //i generally use uniqid() to generate unique filenames
//do whatever with you file
//move it to a directory, store file info in a DB etc.
//return the filename to the AJAX request
echo $filename;
bar.php
//this script is called when the second form is submitted.
//here you can access the filename generated by the first form
$filename = $_POST['filename'];
//do your stuff here
use the Jquery Form plugin to upload the file via Ajax
$(document).ready(function(){
$('yourform').submit(function(){ //the user has clicked on submit
//do your error checking and form validation here
if (!errors)
{
$('yourform').ajaxSubmit(function(data){ //submit the form using the form plugin
alert(data); //here data will be the filename returned by the first PHP script
});
}
});
});
As you'll notice, you haven't specified either the POST data or the URL of the PHP script. ajaxSubmit picks up the POST data from the form automatically and submits it to the URL specified in the action of the form
I can think of two ways off the top of my head.
1.
session_start();
$_SESSION['user'] = $row['user_id']
Then, you can refer to $_SESSION['user'] whenever until the session is destroyed.
Another way would be to include the file that defines $user_id (foo.php) into file1.php with:
include("file1.php");
It is probably easier to achieve this with sessions.
Actually, ONE MORE THING you could use is to pass the variable value through the URL if it isn't something that needs to be kept private.
echo "<a href='file1.php?userid=" .$userid. "' > LINK </a>";
or
<?php
echo "
<html>
<head>
<meta HTTP-EQUIV='REFRESH' content='0; url=file1.php?userid=" .$userid. "'>
</head>
</html>";
Then, on file1.php you would access that variable like this.
$userid = $_GET['userid'];
and you can use $userid as you please.
Can I use a PUT method in an HTML form to send data from the form to a server?
According to the HTML standard, you can not. The only valid values for the method attribute are get and post, corresponding to the GET and POST HTTP methods. <form method="put"> is invalid HTML and will be treated like <form>, i.e. send a GET request.
Instead, many frameworks simply use a POST parameter to tunnel the HTTP method:
<form method="post" ...>
<input type="hidden" name="_method" value="put" />
...
Of course, this requires server-side unwrapping.
XHTML 1.x forms only support GET and POST. GET and POST are the only allowed values for
the "method" attribute.
Can I use "Put" method in html form to send data from HTML Form to server?
Yes you can, but keep in mind that it will not result in a PUT but a GET request. If you use an invalid value for the method attribute of the <form> tag, the browser will use the default value get.
HTML forms (up to HTML version 4 (, 5 Draft) and XHTML 1) only support GET and POST as HTTP request methods. A workaround for this is to tunnel other methods through POST by using a hidden form field which is read by the server and the request dispatched accordingly. XHTML 2.0 once planned to support GET, POST, PUT and DELETE for forms, but it's going into XHTML5 of HTML5, which does not plan to support PUT. [update to]
You can alternatively offer a form, but instead of submitting it, create and fire a XMLHttpRequest using the PUT method with JavaScript.
_method hidden field workaround
The following simple technique is used by a few web frameworks:
add a hidden _method parameter to any form that is not GET or POST:
<input type="hidden" name="_method" value="PUT">
This can be done automatically in frameworks through the HTML creation helper method.
fix the actual form method to POST (<form method="post")
processes _method on the server and do exactly as if that method had been sent instead of the actual POST
You can achieve this in:
Rails: form_tag
Laravel: #method("PATCH")
Rationale / history of why it is not possible in pure HTML: https://softwareengineering.stackexchange.com/questions/114156/why-there-are-no-put-and-delete-methods-in-html-forms
for people using laravel
<form method="post" ...>
#csrf
#method('put')
...
</form>
Unfortunately, modern browsers do not provide native support for HTTP PUT requests. To work around this limitation, ensure your HTML form’s method attribute is “post”, then add a method override parameter to your HTML form like this:
<input type="hidden" name="_METHOD" value="PUT"/>
To test your requests you can use "Postman" a google chrome extension
To set methods PUT and DELETE I perform as following:
<form
method="PUT"
action="domain/route/param?query=value"
>
<input type="hidden" name="delete_id" value="1" />
<input type="hidden" name="put_id" value="1" />
<input type="text" name="put_name" value="content_or_not" />
<div>
<button name="update_data">Save changes</button>
<button name="remove_data">Remove</button>
</div>
</form>
<hr>
<form
method="DELETE"
action="domain/route/param?query=value"
>
<input type="hidden" name="delete_id" value="1" />
<input type="text" name="delete_name" value="content_or_not" />
<button name="delete_data">Remove item</button>
</form>
Then JS acts to perform the desired methods:
<script>
var putMethod = ( event ) => {
// Prevent redirection of Form Click
event.preventDefault();
var target = event.target;
while ( target.tagName != "FORM" ) {
target = target.parentElement;
} // While the target is not te FORM tag, it looks for the parent element
// The action attribute provides the request URL
var url = target.getAttribute( "action" );
// Collect Form Data by prefix "put_" on name attribute
var bodyForm = target.querySelectorAll( "[name^=put_]");
var body = {};
bodyForm.forEach( element => {
// I used split to separate prefix from worth name attribute
var nameArray = element.getAttribute( "name" ).split( "_" );
var name = nameArray[ nameArray.length - 1 ];
if ( element.tagName != "TEXTAREA" ) {
var value = element.getAttribute( "value" );
} else {
// if element is textarea, value attribute may return null or undefined
var value = element.innerHTML;
}
// all elements with name="put_*" has value registered in body object
body[ name ] = value;
} );
var xhr = new XMLHttpRequest();
xhr.open( "PUT", url );
xhr.setRequestHeader( "Content-Type", "application/json" );
xhr.onload = () => {
if ( xhr.status === 200 ) {
// reload() uses cache, reload( true ) force no-cache. I reload the page to make "redirects normal effect" of HTML form when submit. You can manipulate DOM instead.
location.reload( true );
} else {
console.log( xhr.status, xhr.responseText );
}
}
xhr.send( body );
}
var deleteMethod = ( event ) => {
event.preventDefault();
var confirm = window.confirm( "Certeza em deletar este conteúdo?" );
if ( confirm ) {
var target = event.target;
while ( target.tagName != "FORM" ) {
target = target.parentElement;
}
var url = target.getAttribute( "action" );
var xhr = new XMLHttpRequest();
xhr.open( "DELETE", url );
xhr.setRequestHeader( "Content-Type", "application/json" );
xhr.onload = () => {
if ( xhr.status === 200 ) {
location.reload( true );
console.log( xhr.responseText );
} else {
console.log( xhr.status, xhr.responseText );
}
}
xhr.send();
}
}
</script>
With these functions defined, I add a event listener to the buttons which make the form method request:
<script>
document.querySelectorAll( "[name=update_data], [name=delete_data]" ).forEach( element => {
var button = element;
var form = element;
while ( form.tagName != "FORM" ) {
form = form.parentElement;
}
var method = form.getAttribute( "method" );
if ( method == "PUT" ) {
button.addEventListener( "click", putMethod );
}
if ( method == "DELETE" ) {
button.addEventListener( "click", deleteMethod );
}
} );
</script>
And for the remove button on the PUT form:
<script>
document.querySelectorAll( "[name=remove_data]" ).forEach( element => {
var button = element;
button.addEventListener( "click", deleteMethod );
</script>
_ - - - - - - - - - - -
This article https://blog.garstasio.com/you-dont-need-jquery/ajax/ helps me a lot!
Beyond this, you can set postMethod function and getMethod to handle POST and GET submit methods as you like instead browser default behavior. You can do whatever you want instead use location.reload(), like show message of successful changes or successful deletion.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
JSFiddle: https://jsfiddle.net/enriquerene/d6jvw52t/53/
If you are using nodejs, you can install the package method-override that lets you do this using a middleware.
Link to documentation: http://expressjs.com/en/resources/middleware/method-override.html
After installing this, all I had to do was the following:
var methodOverride = require('method-override')
app.use(methodOverride('_method'))
I wrote an npm package called 'html-form-enhancer'. By dropping it into your HTML source, it takes over submission of forms with methods aside from GET and POST, and also adds application/json serialization.
<script type=module" src="html-form-enhancer.js"></script>
<form method="PUT">
...
</form>
In simple words - No.
I have tried to fire a put request in the HTML form, but it sends the POST request to the server. To add the PUT request -
We can do it by listening to the submit action in the script, then fire the put request to a particular endpoint.
Screenshot from the http-server env. test
Consider this form:
<form action="http://www.blabla.com?a=1&b=2" method="GET">
<input type="hidden" name="c" value="3" />
</form>
When submitting this GET form, the parameters a and b are disappearing.
Is there a reason for that?
Is there a way of avoiding this behaviour?
Isn't that what hidden parameters are for to start with...?
<form action="http://www.example.com" method="GET">
<input type="hidden" name="a" value="1" />
<input type="hidden" name="b" value="2" />
<input type="hidden" name="c" value="3" />
<input type="submit" />
</form>
I wouldn't count on any browser retaining any existing query string in the action URL.
As the specifications (RFC1866, page 46; HTML 4.x section 17.13.3) state:
If the method is "get" and the action is an HTTP URI, the user agent takes the value of action, appends a `?' to it, then appends the form data set, encoded using the "application/x-www-form-urlencoded" content type.
Maybe one could percent-encode the action-URL to embed the question mark and the parameters, and then cross one's fingers to hope all browsers would leave that URL as it (and validate that the server understands it too). But I'd never rely on that.
By the way: it's not different for non-hidden form fields. For POST the action URL could hold a query string though.
In HTML5, this is per-spec behaviour.
See Association of controls and forms - Form submission algorithm.
Look at "4.10.22.3 Form submission algorithm", step 17. In the case of a GET form to an http/s URI with a query string:
Let destination be a new URL that is equal to the action except that
its <query> component is replaced by query (adding a U+003F QUESTION
MARK character (?) if appropriate).
So, your browser will trash the existing "?..." part of your URI and replace it with a new one based on your form.
In HTML 4.01, the spec produces invalid URIs - most browsers didn't actually do this though...
See Forms - Processing form data, step four - the URI will have a ? appended, even if it already contains one.
What you can do is using a simple foreach on the table containing the GET information. For example in PHP :
foreach ($_GET as $key => $value) {
$key = htmlspecialchars($key);
$value = htmlspecialchars($value);
echo "<input type='hidden' name='$key' value='$value'/>";
}
As the GET values are coming from the user, we should escape them before printing on screen.
You should include the two items (a and b) as hidden input elements as well as C.
I had a very similar problem where for the form action, I had something like:
<form action="http://www.example.com/?q=content/something" method="GET">
<input type="submit" value="Go away..." />
</form>
The button would get the user to the site, but the query info disappeared so the user landed on the home page rather than the desired content page. The solution in my case was to find out how to code the URL without the query that would get the user to the desired page. In this case my target was a Drupal site, so as it turned out /content/something also worked. I also could have used a node number (i.e. /node/123).
If you need workaround, as this form can be placed in 3rd party systems, you can use Apache mod_rewrite like this:
RewriteRule ^dummy.link$ index.php?a=1&b=2 [QSA,L]
then your new form will look like this:
<form ... action="http:/www.blabla.com/dummy.link" method="GET">
<input type="hidden" name="c" value="3" />
</form>
and Apache will append 3rd parameter to query
When the original query has array, for php:
foreach (explode("\n", http_build_query($query, '', "\n")) as $keyValue) {
[$key, $value] = explode('=', $keyValue, 2);
$key = htmlspecialchars(urldecode($key), ENT_COMPAT | ENT_HTML5);
$value = htmlspecialchars(urldecode($value), ENT_COMPAT | ENT_HTML5);
echo '<input type="hidden" name="' . $key . '" value="' . $value . '"' . "/>\n";
}
To answer your first question yes the browser does that and the reason is
that the browser does not care about existing parameters in the action URL
so it removes them completely
and to prevent this from happening use this JavaScript function that I wrote
using jQuery in:
function addQueryStringAsHidden(form){
if (form.attr("action") === undefined){
throw "form does not have action attribute"
}
let url = form.attr("action");
if (url.includes("?") === false) return false;
let index = url.indexOf("?");
let action = url.slice(0, index)
let params = url.slice(index);
url = new URLSearchParams(params);
for (param of url.keys()){
let paramValue = url.get(param);
let attrObject = {"type":"hidden", "name":param, "value":paramValue};
let hidden = $("<input>").attr(attrObject);
form.append(hidden);
}
form.attr("action", action)
}
My observation
when method is GET and form is submitted, hidden input element was sent as query parmater. Old params in action url were wiped out. So basically in this case, form data is replacing query string in action url
When method is POST, and form is submitted, Query parameters in action url were intact (req.query) and input element data was sent as form data (req.body)
So short story long, if you want to pass query params as well as form data, use method attribute as "POST"
This is in response to the above post by Efx:
If the URL already contains the var you want to change, then it is added yet again as a hidden field.
Here is a modification of that code as to prevent duplicating vars in the URL:
foreach ($_GET as $key => $value) {
if ($key != "my_key") {
echo("<input type='hidden' name='$key' value='$value'/>");
}
}
Your construction is illegal. You cannot include parameters in the action value of a form. What happens if you try this is going to depend on quirks of the browser. I wouldn't be surprised if it worked with one browser and not another. Even if it appeared to work, I would not rely on it, because the next version of the browser might change the behavior.
"But lets say I have parameters in query string and in hidden inputs, what can I do?" What you can do is fix the error. Not to be snide, but this is a little like asking, "But lets say my URL uses percent signs instead of slashes, what can I do?" The only possible answer is, you can fix the URL.
I usually write something like this:
foreach($_GET as $key=>$content){
echo "<input type='hidden' name='$key' value='$content'/>";
}
This is working, but don't forget to sanitize your inputs against XSS attacks!
<form ... action="http:/www.blabla.com?a=1&b=2" method ="POST">
<input type="hidden" name="c" value="3" />
</form>
change the request method to' POST' instead of 'GET'.