views:

2453

answers:

11

What's the best way to get a regular anchor (<a href="...">) to submit the form it is embedded in when clicked?

<form>
    <ul>
        <li>
            <p>
                The link could be <span>embedded <a href="" onclick="?">at any level</a></span>
                in the form, so "this.parentNode.parentNode..." is no good. :(
            </p>
        </li>
    </ul>
</form>

I know that the easiest way using jQuery would be

$('#myLink').click(function() {
    $(this).parents('form:first').submit();
});

...but I'm trying to find a way to do this without using a library.


Edit: I'm really trying to find a method which doesn't require knowledge of the form (eg: its name, id, etc). This would be similar to how you could put this on an input element: <input onclick="this.form.submit()" />

+10  A: 

Why don't you use an <input> or <button> element and just tweak it with CSS? Then it works without Javascript and is therefore more reliable.

ypnos
You can't do button:hover on IE6.
nickf
button/input-submit behaves better, more like the thing you are trying to model, so it's a better choice even if JS is guaranteed available. href="#" will behave strangely if you eg. middle-click it, right-click-bookmark etc. If hover on IE6 is actually important you can always put a JS hack in.
bobince
Agree with this answer. Links are meant to be GET requests, and there's no reason to change it. Don't make links do POST. Use form submits instead.
Rakesh Pai
yeah, it's not the answer to the question though, is it? I know that you can use an input to submit a form and that it's semantically better, etc, but I wanted to know about a regular <a> link.
nickf
See other, very good, answers then. Sorry if mine is not helpful for you. Problem is, what you want to do is considered "evil". :D
ypnos
nickf, sometimes the correct answer is that the question is wrongheaded.
eyelidlessness
+2  A: 

The simplest way to do that would be use something like this:


<a href="#" onclick="document.formName.submit();">
Vinny Carpenter
I would change that to:<a href="#" onclick="document.formName.submit(); return false;">The reason for the change is that although it's not supposed to happen, it's entirely possible that a browser might end up redirecting to the # link before the form is submitted, thereby screwing things up.
Chris
this is what i've ended up using, but was really hoping for a way to do it without needing to know anything about the form (eg, its name)
nickf
+1  A: 

Vinny's answer is correct. The question supports a comment I made some time ago -- using frameworks is a great convenience but it is really better programming to do it the hard way until you understand what the framework is doing. Just grabbing stuff off the web and using it is dangerous. Do you know the security implication of what you are doing, if you don't know what it is really doing? What if the functionality breaks due to other script on your page or a browser upgrade? Can you fix it then?

Devin Ceartas
+1  A: 

best way is

<a href="#" onclick="document.forms[0].submit();return false;">Submit Form</a>

however you probably DON'T want to do that as it will make submitting impossible for users with JS disabled

Andrew G. Johnson
You could put a <noscript> with the submit button. Users with JS enabled will see the link with its pretty hover, and users with JS disabled will see a standard button -without hover in IE6, of course.
ARemesal
@ARemesal: good point! i hadn't considered noscript
nickf
Didn't think of that, in fact you may want to not even have the link in HTML, just add it programmatically via JS so that they won't see it all all without JS enabled
Andrew G. Johnson
+2  A: 

loop through parent nodes until you find an element with tagname that indicates it's a form!

<form>
    <ul>
        <li>
            <p>
                The link could be <span>embedded <a href="" onclick="get_form(this).submit(); return false">at any level</a></span>
                in the form, so "this.parentNode.parentNode..." is no good. :(
            </p>
        </li>
    </ul>
</form>



<script type="text/javascript">
    //<![CDATA[
    function get_form( element )
    {
        while( element )
        {
            element = element.parentNode
            if( element.tagName.toLowerCase() == "form" )
            {
                //alert( element ) //debug/test
                return element
            }
        }
        return 0; //error: no form found in ancestors
    }
    //]]>
</script>
hasen j
+1  A: 

Similar solution to hasen j, but using a recursive function to traverse the document.

function findParentForm(element) {
    if (element.parentNode.tagName.toLowerCase() == 'html') {
     throw('No Parent Form Found');
    } else if (element.parentNode.tagName.toLowerCase() == 'form') {
     return element.parentNode;
    } else {
     return findParentForm(element.parentNode);
    }
}

And the form, of course...

<form>
    <ul>
     <li>
      <p>
       The link could be <span>embedded <a href="" onclick="findParentForm(this).submit(); return false;">at any level</a></span>
       in the form, so "this.parentNode.parentNode..." is no good. :(
      </p>
     </li>
    </ul>
</form>
enobrev
is there a reason why you'd use recursion instead of a loop? isn't the overhead going to be larger with recursion? (obviously negligible at this level, but still?)
nickf
Not sure about the efficiency. Wouldn't be hard to test with firebug. I wrote this example before I saw hasan j's answer. I was surprised his worked (tested it to be sure) and glad to have learned something, but figured I'd post mine as well anyway.
enobrev
A: 

Personally, I prefer to use the javascript: protocol in the href instead of using onclick event... If there is any issues with this, I would be happy to be corrected.

If you have only one form in the page, a quite common case, you can do simply:

<li><p><a href="javascript:document.forms[0].submit();">Click here to submit</a></p></li>

Otherwise, bubbling up the elements as above is a solution.

[EDIT] I keep the answer, even if it is downvoted, as a reference (the info given in comments is interesting).
Another drawback of the protocol technique: it doesn't generate an event object. Not a problem in the snippet I gave, but annoying when calling a handler.

PhiLho
what is with documents.forms[0]? Won't that be completely wrong should there be more than one form on the page before this one?
nickf
That's what I wrote: it is reliable only if you are sure to have only one form.
PhiLho
The javascript pseudo-protocol can trigger unexpected behavior (commonly no new images/dead script thread), it has security issues on IE in HTTPS mode, failure to include a return may redirect to strange places (try "javascript:document.body.style.display='block';"). It also fails for non-JS users.
Borgar
@Borgar: thanks for the head ups, it is interesting. So outside of https and expressions with values (which I avoid also, like for bookmarklets), it should be OK... Failing for non-JS users is also true for the other form, anyway.
PhiLho
The reason for the lack of an event on javascript: click is that the browser thinks that you are navigating away from the page and therefore shuts services down. To avoid this mess, I recommend sticking to onclick (except in the case of bookmarklets). :-)
Borgar
+1  A: 

You should use a button (and input or button of type submit) to submit a form.

If you need any additional features that a link has but input elements don't have (such as hover), then it is easier to implement those with javascript, than it is the submission of the form. It will also degrade more gracefully for people without javascript.

You can even solve this with MSIE specific code (and use :hover for other browsers):

<input type="submit" value="send" class="linkstyles"
       onmouseenter="this.className+=' hovered';"
       onmouseleave="this.className=this.className.replace(/(^|\s)hovered(\s|$)/g, '');" />

If you still really really want to do it backwards then here's how I wouldn't do it:

function submitByLink ( elm ) {
  // Move up domtree until we hit no parentNode or find a form
  while (elm) {
    elm = elm.parentNode;
    if (elm && elm.tagName == 'FORM') {
      // First chance we get, we submit the form and exit.
      // The return on the node it kills the event bubble by forwarding false to browser
      elm.submit(); 
      return false;
    }
  }
  // If we got here then there is no form parent and user will be sent to link href
}

And the HTML would look like this:

<a href="aPageExplainingWhyYouNeedJavascript.html" onclick="return submitByLink(this);">Send</a>
Borgar
A: 
$(document).ready(function(){$('#submit').click(function(){$('#signup').submit();});});

Using Jquery, we check the document has loaded, then we wait for an anchor tag with an id of 'submit' to be clicked. It then submits the form with an id of 'signup'. Change 'submit' and 'signup' to suit.

Gav
A: 

Hi! I am using this now every time. Because the submit button in my project usually a link (by wrap an image or CSS), so I use this:

<a href="#" onclick="$(this).closest('form').submit(); return false;">Submit</a>

Don't forget it is using jQuery too.

You can wrap in your own function. So it always submit the parent element (form) on that link.

Jef
A: 

As long as the link is a direct child of the form, you can use this. You don't need to know the name of the form. Works in at least Firefox and Chrome.

<form action="">
    <a href="" onclick="parentNode.submit();return false;">Submit</a>
</form>

quirksmode.org tells me x.parentNode works in all browsers, so this should work everywhere.

Graham King