Every web user is familiar with both links and forms. Links are easy because you just click, whereas forms require you to type in information and make selections. But what if you could submit certain forms as simply as clicking on a link?
As it happens, you can already submit some forms via a link. It all depends on what method the form developer specified. The term method refers to the manner in which a web page interacts with the server on which it's hosted. Most regular web pages use the GET method, which is the most familiar and easiest to understand. Web forms can also use GET. For instance, if you go to Google:
and search for, say, albino crustaceans, you'll get something like the following:
https://www.google.com/search?q=albino+crustaceans
By just clicking on the second link, you can repeat the search. You can now save that search by bookmarking it, including it in a web page or blog post, emailing it to someone, and so on.
However, many forms use the POST method. You can usually tell the difference by looking at the web address after you’ve submitted the form. If you don’t see a question mark followed by some text that contains at least some of the information you entered (as with the Google example above), it’s likely the form used the POST method. If you want to repeat the submission, copying the address of the submitted form won’t work (another way to test). Other than filling the form again, what are your alternatives?
Security, and other concerns
Before we look at alternatives, it’s important to note that there are good reasons for developers preferring the POST method. The very convenience that GET provides – all the information is passed in the address itself – makes it inherently insecure: if a login or checkout form worked this way, it would be disastrous. Also, certain POST forms are so specific or so detailed that they would never need to be replicated. In the real world, only a minority of POST forms lend themselves to a single-click workaround.
A real world example: running a GTMetrix test
GTMetrix is a site that allows you to test the performance of any website by entering the URL and clicking the Analyze button. Once the analysis is complete, you get an URL that you can save, but that only gives you access to a time-limited report. If you want to run the test again, you have to reenter the URL and click Analyze.
Enter HTML5 and JavaScript
To get our link to run a GTMetrix test with a single click, we want to (i) encode all the necessary information to be submitted in the link itself and (ii) configure the link to submit the data via POST rather than GET.
Pass information using HTML5's data-*
attributes
Encoding information in a link is an excellent use case for HTML5’s data-*
attributes. We can change the basic link structure from:
<a href="https://gtmetrix.com/">Analyse site in GTMetrix</a>
to:
<a data-postdata-target="https://gtmetrix.com/analyze.html?bm" data-postdata-params='{"url":"http://www.cdelaney.com/"}' href="https://gtmetrix.com/">Analyse site in GTMetrix</a>
The first link merely loads the main GTMetrix page. The second also passes all the necessary information in data-*
attributes. The actual URL the GTMetrix form submits to is the value of the data-postdata-target
attribute (merely linking to this URL would return an error). The information that gets sent to the GTMetrix form is the value of the data-postdata-params
attribute, stored as a JSON array. Although the specifics of the JSON notation are beyond the scope of this post, note that it’s crucial that the value of this attribute is enclosed in single quotes, and that the keys and values inside the single quotes are enclosed in double quotes: a rare instance where HTML(5) is absolutely unforgiving.
Submit the content of the link via the POST method
Now that we’ve got the content of the link ready, we must change the behaviour of the link so that it submits our data via POST instead of retrieving the target page via GET. The simplest way to do this is via JavaScript. In plain English, whenever someone clicks on our link, we’re going to do the following:
- Prevent the link from interrupting our submission i.e. don’t let it load another page.
- Capture the data that’s stored in our
data-*
attributes - Create a new window on the fly, complete with an (invisible) web form replicating the necessary fields from the form we’re emulating, each one populated with the data we want to send.
- Submit this form and see the result
The code
I originally wrote this in jQuery, but then I thought to myself Self, don’t be lazy. It’s a relatively simple function, with nothing that any reasonably modern browser couldn’t do with plain JavaScript.
So I rewrote it in plain JavaScript, which also made it easy to turn it into a bookmarklet (see below). If your project is already using jQuery, then rewriting it in jQuery should save about 10% in file size, if you care about such things (I do).
Anyway, here it is. Just copy and paste this either into a <script>
tag in your document, or add it to a linked JavaScript file.
(function (){
var postLinks = document.querySelectorAll('a[data-postdata-params]');
for (var i = 0, len = postLinks.length; i < len; i++){
postLinks[i].addEventListener('click', function (e) {
e.preventDefault();
var target = this.getAttribute('data-postdata-target') || this.getAttribute('href'),
paramsToPost = JSON.parse(this.getAttribute('data-postdata-params')),
postToUrl = function(path, params, method) {
var openWindow = window.open(path),
form = openWindow.document.createElement('form');
method = method || 'post';
form.setAttribute('method', method);
form.setAttribute('action', path);
for (var key in params) {
if (params.hasOwnProperty(key)) {
var hiddenField = document.createElement('input');
hiddenField.setAttribute('type', 'hidden');
hiddenField.setAttribute('name', key);
hiddenField.setAttribute('value', params[key]);
form.appendChild(hiddenField);
}
}
openWindow.document.body.appendChild(form);
form.submit();
};
postToUrl(target, paramsToPost);
}, false);
}
})();
Demo
Because this functionality requires JavaScript, we must consider the use case where the user’s browser cannot (or does not) execute JavaScript. Perhaps their browser is very old or very basic, or maybe the page rendered OK but the script didn’t download. In this situation, our link will revert to its default behaviour, and will take you to the address specified in the href
attribute. The solution, then, is to provide the address of the page containing the form as the href
attribute. With JavaScript disabled, clicking the link will simply load the page containing the form, leaving the user to fill in the data themselves: an acceptable fallback.
Demo
Here’s a “regular” link to GTMetrix, which just takes you to the form:
And here's the same link, recoded to submit this page to GTMetrix in one click:
Bonus: converting the script to a bookmarklet
Because our script is written as a self-executing anonymous function, it’s a small extra step to turn it into a bookmarklet, which you can then add to your Bookmarks/Favorites.
- First, make sure that your Bookmarks/Favorites bar is visible. If not, click Ctrl-B (Cmd-B on Mac) for Firefox, or Ctrl-Shift-I (Cmd-Shift-I on Mac) for Internet Explorer
- Then drag the link below to your Bookmarks/Favorites bar and release it. It should appear with the label
TestInGTMetrix,
either where you release the mouse button, or at the bottom of your Bookmarks/Favorites bar.
To use it, just click on your Test In GTMetrix Bookmark/Favorite whenever you're viewing a page that you want to test in GTMetrix.