views:

76330

answers:

15

I'm trying to direct a browser to a different page. If I wanted a GET request, I might say

document.location.href = 'http://example.com/q=a';

But the resource I'm trying to access won't respond properly unless I use a POST request. If this were not dynamically generated, I might use the HTML

<form action="http://example.com/" method="POST">
  <input type="hidden" name="q" value="a">
</form>

Then I would just submit the form from the DOM.

But really I would like JavaScript that allows me to say

post_to_url('http://example.com/', {'q':'a'});

What's the best cross browser implementation?

Edit I'm sorry I was not clear. I need a solution that changes the location of the browser, just like submitting a form. If this is possible with XMLHTTPRequest, it is not obvious. And this should not be asynchronous, nor use XML, so AJAX is not the answer.

+5  A: 

You can dynamically create a form, and then post that.

AaronSieb
+1  A: 

You could dynamically add the form using DHTML then submit

AnthonyWJones
A: 

You could make an AJAX call (likely using a library such as using Prototype.js or JQuery). AJAX can handle both GET and POST options.

Diodeus
Using XMLHttpRequest wouldn't direct the browser to another page.
insin
A: 

You could use a library like JQuery and its $.post method.

Bill Turner
+2  A: 

Three options here.

  1. Standard Javascript Answer: Use a framework! Most Ajax frameworks will have abstracted you an easy way to make an XMLHTTPRequest POST

  2. Make the XMLHTTPRequest request yourself, passing post into the open method instead of get. (more info)

  3. Via Javascript, dynamically create a form, add an action, add your inputs, and submit that.

Alan Storm
XMLHTTPRequest doesn't update the window. Are you trying to say I should end with the AJAX with a document.write(http.responseText)?
Joseph Holsten
A: 

The Prototype library includes a Hashtable object, with a ".toQueryString()" method, which allows you to easily turn a javascript Object/structure into a query-string style string. Since the post requires the "body" of the request to be a query-string formatted string, this allows your AJAX reqest to work properly as a post. Here's an example using prototype:

$req = new Ajax.Request("http://foo.com/bar.php",{
  method: 'post',
  parameters: $H({
    name: 'Diodeus',
    question: 'Javascript Post Request like a Form Request',
    ...
  }).toQueryString();
};
Adam N
+56  A: 
function post_to_url(path, params, method) {
    method = method || "post"; // Set method to post by default, if not specified.

    // The rest of this code assumes you are not using a library.
    // It can be made less wordy if you use one.
    var form = document.createElement("form");
    form.setAttribute("method", method);
    form.setAttribute("action", path);

    for(var key in params) {
        var hiddenField = document.createElement("input");
        hiddenField.setAttribute("type", "hidden");
        hiddenField.setAttribute("name", key);
        hiddenField.setAttribute("value", params[key]);

        form.appendChild(hiddenField);
    }

    document.body.appendChild(form);    // Not entirely sure if this is necessary
    form.submit();
}

There is more stuff you can do - cleanup after DOM manipulation, ensuring that the keys is part of the hasOwnProperty list, etc., but this should get you started.

Rakesh Pai
Your guess was right, it's not necessary to append the form. Looks good
Joseph Holsten
This doesn't work in IE, as the name won't be set on the hidden fields: http://msdn.microsoft.com/en-us/library/ms534184(VS.85).aspx
insin
for IE6 it is required to append the form to the document in order to submit it. (example as shown works fine fine in IE6)
Jacco
In FireFox 3.0.10 the document.body.appendChild(form); is necessary. However in Safari its not necessary.
neoneye
Can you pass a relative path to it?. eg. post_to_url('/example',{"foo":"bar"})
Albert
Sure. Relative paths work fine too.
Rakesh Pai
very useffull , i have to upload file direct by js and your solution is very good
Chameron
+5  A: 

Using the createElement function provided in this answer, which is necessary due to IE's brokenness with the name attribute on elements created normally with document.createElement:

function postToURL(url, values)
{
    values = values || {};

    var form = createElement("form", {action: url,
                                      method: "POST",
                                      style: "display: none"});
    for (var property in values)
    {
        if (values.hasOwnProperty(property))
        {
            var value = values[property];
            if (value instanceof Array)
            {
                for (var i = 0, l = value.length; i < l; i++)
                {
                    form.appendChild(createElement("input", {type: "hidden",
                                                             name: property,
                                                             value: value[i]}));
                }
            }
            else
            {
                form.appendChild(createElement("input", {type: "hidden",
                                                         name: property,
                                                         value: value}));
            }
        }
    }
    document.body.appendChild(form);
    form.submit();
    document.body.removeChild(form);
}
insin
+3  A: 

A simple quick'n'dirty implementation of @Aaron answer :

document.body.innerHTML += '<form id="dynForm" action="http://example.com/" method="post"><input type="hidden" name="q" value="a"></form>';
document.getElementById("dynForm").submit();

Of course, you should rather use a javascript framework such as Prototype or jQuery...

Alexandre Victoor
Is there a way to do this without there being a web page loaded in the current browser window/tab?
pbreitenbach
A: 
Katy
A: 

This is like Alan's option 2 (above). How to instantiate the httpobj is left as an excercise.

httpobj.open("POST", url, true);
httpobj.setRequestHeader('Content-Type','application/x-www-form-urlencoded; charset=UTF-8');
httpobj.onreadystatechange=handler;
httpobj.send(post);
Revah
+1  A: 

One solution is to generate the form and submit it. One implementation is

function post_to_url(url, params) {
    var form = document.createElement('form');
    form.action = url;
    form.method = 'POST';

    for (var i in params) {
        if (params.hasOwnProperty(i)) {
            var input = document.createElement('input');
            input.type = 'hidden';
            input.name = i;
            input.value = params[i];
            form.appendChild(input);
        }
    }

    form.submit();
}

So I can implement a URL shortening bookmarklet with a simple

javascript:post_to_url('http://is.gd/create.php', {'URL': location.href});
Joseph Holsten
+8  A: 

If you have Prototype installed, you can tighten up the code to generate and submit the hidden form like this:

 var form = new Element('form',
                        {method: 'post', action: 'http://example.com/'});
 form.insert(new Element('input',
                         {name: 'q', value: 'a', type: 'hidden'}));
 $(document.body).insert(form);
 form.submit();
Head
A: 

Rakesh Pai answer is amazing but there is an issue that occurs for me (in safari) when you try to post a form with a field called submit. For example post_to_url("http://google.com/",{ submit: "submit" } );. I have patched the function slightly to walk around this variable space collision.

    function post_to_url(path, params, method) {
        method = method || "post";

        var form = document.createElement("form");

        //move the submit function to another variable
        //so that it doesn't get over written
        form._submit_function_ = form.submit;

        form.setAttribute("method", method);
        form.setAttribute("action", path);

        for(var key in params) {
            var hiddenField = document.createElement("input");
            hiddenField.setAttribute("type", "hidden");
            hiddenField.setAttribute("name", key);
            hiddenField.setAttribute("value", params[key]);

            form.appendChild(hiddenField);
        }

        document.body.appendChild(form);
        form._submit_function_(); //call the renamed function
    }
    post_to_url("http://google.com/", { submit: "submit" } ); //works!
Kendall Hopkins
A: 

Here is how I wrote it using JQuery. Tested in firefox and IE.

function postToUrl(url, params, newWindow)
{
    var form = $('<form>');
    form.attr('action', url);
    form.attr('method', 'POST');
    if(newWindow){ form.attr('target', '_blank'); }

    var addParam = function(paramName, paramValue){
        var input = $('<input type="hidden">');
        input.attr({ 'id':     paramName,
                     'name':   paramName,
                     'value':  paramValue });
        form.append(input);
    };

    // Params is an Array.
    if(params instanceof Array){
        for(var i=0; i<params.length; i++){
            addParam(i, params[i]);
        }
    }

    // Params is an Associative array or Object.
    if(params instanceof Object){
        for(var key in params){
            addParam(key, params[key]);
        }
    }

    // Submit the form, then remove it from the page
    form.appendTo(document.body);
    form.submit();
    form.remove();
}
beauSD