IE sends inner HTML when clicking on a button elem

2019-03-19 22:39发布

问题:

I have the following html in my webpage (simplified).

<button type="submit" name="action" value="ButtonA">Click Here</button>

In Firefox, it submits "ButtonA" as the value for the "action" form value. However, in IE7, it submits "Click Here". Is there any way to resolve this? I don't want to use input tags, because I need to be able to customize the text without affecting the values sent back to the form (localization). Basically, I want to be able to have multiple buttons with the same name, and depending on their value, do a different action when submitted. Is there any easy with to get IE to act correctly in this case?

[MORE]

Maybe I should be more clear, but I can't use

<input type="submit" name="Action" value="ButtonA">

because I need to be able to change the text displayed for localization rules, without affecting the actual value of the button that's submitted with the form.

[MORE]

To elaborate even more, Basically, I want the button to be able to say "Save" or "Sauver" depending on the language, but not have the value submitted to the server change. I also want to have multiple buttons with the same name, and depending on the value, do something, rather than depending on the button name, and testing if there is a value for that button. The code is already written from that perspective, and I just want to be able to change the displayed text in the values, without existing server side processing code.

Here is a link with a very good explanation of the problem, with some possible work arounds.

回答1:

One solution is to use Javascript and a hidden field

   <input type="hidden" name="actionparam" value="DoNothing">
   <input type="button" onclick="OnSubmitForm('ActionA')" Value="Click Here for A" />
   <input type="button" onclick="OnSubmitForm('ActionB')" Value="Click Here for B" />


   function OnSubmitForm(actionname) {
    var f = document.frm;
    f.actionparam.value = actionname;
    f.submit();
 }

This works as a hidden CATPCHA also, and you can add some client validation in the javascript function

Edit:

Since you say you want to degrade to non-javascript browsers, you can use this version, that allow only one default action to the people with no javascript

The extra buttons are disabled in HTML but then re-enabled with javascript.
Tested code:

<html>
<head>
    <script type="text/javascript">
    <!--
    function OnSubmitForm(actionname) {
            var f = document.frm;
            f.actionparam.value = actionname;
            f.submit();
    }
    //-->
    </SCRIPT>
</head>
<body>
   <noscript>
        <div style="background-color: yellow; margin: 20px;" >
            You are using a limited version of the site because you don't have Javascript enabled
        </div>
    </noscript>


   <h1>form</h1>
    <form name="frm" method="post">
    <input type="hidden" name="actionparam" value="DefaultAction" />
    <button name="defaultbutton" type="submit">default action</button>
    <button name="extrabutton1" disabled onclick="OnSubmitForm('ExtraAction1')">Extra action 1</button>
    <button name="extrabutton2" disabled onclick="OnSubmitForm('ExtraAction2')">Extra action 2</button>
    </form>


   <h1>Results</h1>
   <h2>forms collection</h2>
   <ol>
   <%
   For x = 1 To Request.Form.count()
      Response.Write("<li>" + Request.Form.key(x) + "=" + Request.Form.item(x) + "</li>")
   Next
   %>
   </ol>


    <script type="text/javascript">
    <!--
    document.frm.extrabutton1.disabled = false;
    document.frm.extrabutton2.disabled = false;
    //-->
    </SCRIPT>

</body>
</html>


回答2:

The usual workaround to get it working with an input-submit is to munge the value into multiple 'name' attributes, eg.:

<input type="submit" name="submit.buttonA" value="Sausage" />
<input type="submit" name="submit.buttonB" value="Mash" />

The form layer I personally use will automatically convert that as if a 'submit' control with value 'buttonA' or 'buttonB' were clicked, but it should be easy to do manually in most environments.



回答3:

Just had to deal with IE6's wonderful implementation of button elements. This solution does rely on Javascript but some may find it useful.

It's particularly annoying when using the AbstractWizardController in the Spring framework as the button element is the ideal solution for the "Next", "Back" and "Finish" buttons of the wizard but don't work in IE6.

So, I ended up writing a small jQuery based fix (though it's quite trivial to convert it so that you don't have to use the jQuery library).

$(function(){
if((window.XMLHttpRequest == undefined) && (ActiveXObject != undefined)) {
    $('button').click( function(event) {
        var rx = /\bvalue ?= ?(".*?"|'.*?')/i;
        var matches = $(this)[0].outerHTML.match( rx );
        if( matches != null )
            $(this).attr( 'value', matches[1].substring( 1, matches[1].length - 1 ) );
        $('button').not( $(this) ).attr('disabled','disabled');
    });
}
}); 

This will add an onclick event to all button elements. When a button is clicked it will grab the outerHTML of the button, e.g.:

<button name="playerId" value="34">Walter Payton</button>

and parse out the value attribute. Seems a lot of trouble to go in order to get the value but I found that getAttributeNode('value').value returned the innerHTML rather than the specified value attribute so wasn't very helpful. We then set the submatch of the regex as the value of the button. It should match it if you use either double or single quotes as delimiters but you do have to use some form of delimiter.

The upshot of this is that instead of "Walter Payton" being posted it will actually post "34" instead. The downside is that the button's appearance on the page will also change to "34" just before the form is submitted.

Finally the script will find all button elements except the clicked one and set their disabled attribute to be disabled. This ensures they aren't included in the POST and you don't get false positives.



回答4:

As Eduardo mentions, JavaScript sounds like your best option. However, you'll need to somehow consider the fact that if a user has JavaScript disabled, you will not receive the appropriate value.



回答5:

I think that you should reconsider this whole concept. I have a feeling your scenario goes something like this:

  • User clicks Save or Cancel
  • Server-side, you check for "Save" or "Cancel" value
  • You perform actions based on this

In reality, it shouldn't matter what the value of a Save button is. In PHP, for example, you can simply check for a value in the Save element. Regardless of whether the value is "Save" or "Sauver", you can perform the saving functionality.

I apologize if I'm way off base here. Let me know if my assumptions are accurate.



回答6:

Good news: Microsoft fixed this in IE8 (standards mode only)

Bad news: It is still in beta

This jQuery fix works alright or you can hack your own JS to handle IE.

As for those suggesting input over button, that's fine, but if you want graphics or different styles on your button, then button is the only way to go.



回答7:

The link you provided in the question explains that IE6 submits all the buttons with every form submission, so your app won't work with IE6 no matter what workaround you use. I tested this and verified that IE6 does indeed do this. This means that without Javascript the <button> tag is useless with IE6, and given the other limitation it is severely limited with IE7 as well. The only non-Javascript workaround I can think of is to put your <button> tags outside your main <form>, in their own forms. You could do this with <a> tags as well, but I can't recommend that since links are always GET requests and GET requests should never have side-effects, such as modifying data.

<div style="float:left">
  <form name="shoppingCart" action="#c" method="GET">
    <input type="hidden" name="item1" value="hat">
    <input type="text" name="item1quantity" value="1"> Hat, red<br>
    <input type="hidden" name="item2" value="scarf">
    <input type="text" name="item2quantity" value="1"> Scarf, red<br>
    <button type="submit" name="button" value="purchase">Buy now!</button>
  </form>  
</div>
<div style="float:right">
  <form name="remove" action="#a" method="GET">
    <input type="hidden" name="item" value="item1">
    <button type="submit" name="button" value="delete1">Remove this item</button>
  </form>
  <form name="remove" action="#b" method="GET">
    <input type="hidden" name="item" value="item2">
    <button type="submit" name="button" value="delete2">Remove this item</button>
  </form>
</div>

The downside of using multiple forms is that you are limited in what you can transmit; if the user changes the quantity in the above form that information won't be submitted when the user clicks 'remove'. But you could consider that graceful degredation for non-JS users, and use JS to synchronize the data in the main form with the hidden forms.



回答8:

I think you should be using an <input type="submit" /> instead of <button>.



回答9:

Use <input> instead of <button>. Otherwise, here's a description of a nice jQuery-based hack.



回答10:

I don't know any way of making it work in IE7 (or IE6) without the need for JavaScript (or strange multi-form constructions).

Isn't that localized accessible to the back-end somehow either? Say, is the text coming from a database or will that just be inline in the local templates or so? You should be able to retrieve the localized version of the label both on printing and on validating the form on the back-end, shouldn't you (as much as you'd rather just use the unchanging value as you should really be able to do)?

There's always the JavaScript solution...

The following is more of a proof-of-concept that'll need some tweaking than a ready-made jQuery one-liner, but it should work without the need to change any of the HTML:

<!doctype html>
<html>

<head>

<title>Fix Buttons in IE6</title>

<script type="text/javascript">
function fixButtons() {
    var btns = document.getElementsByTagName('button');

    for (var i = 0; i < btns.length; i++) {
        btns[i].onclick = fixValue;
    }
}

function fixValue() {
    var btns = document.getElementsByTagName('button');

    for (var j = 0; j < btns.length; j++) {
        if (this == btns[j]) {
            this.value = this.getAttributeNode('value').value;
        }
        else {
            btns[j].parentNode.removeChild(btns[j--]);
        }
    }
}
</script>

</head>

<body onload="fixButtons()">

<form action="" method="get">
    <button type="submit" name="action1" value="value1">Do Action 1</button>
    <button type="submit" name="action2" value="value2">Do Action 2a</button>
    <button type="submit" name="action2" value="value3">Do Action 2b</button>
</form>

</body>

</html>

If it only needs to work in IE7, and not in IE6, the fiXValue() function can be reduced to just:

this.value = this.getAttributeNode('value').value


回答11:

Check out this ie-button-fix project which uses IE behaviors (i.e. javascript) to neatly solve the problem.



回答12:

A simple workaround without using javascript is this:

<button type="submit" name="action" value="ButtonA" onclick="this.value='ButtonA'">Click Here</button>