Thursday, June 7, 2012

Getting jQuery to recognise .change() in IE


I'm using jQuery to hide and show elements when a radio button group is altered/clicked. It works fine in browsers like Firefox, but in IE 6 and 7, the action only occurs when the user then clicks somewhere else on the page.



To elaborate, when you load the page, everything looks fine. In Firefox, if you click a radio button, one table row is hidden and the other one is shown immediately. However, in IE 6 and 7, you click the radio button and nothing will happen until you click somewhere on the page. Only then does IE redraw the page, hiding and showing the relevant elements.



Here's the jQuery I'm using:




$(document).ready(function(){

$(".hiddenOnLoad").hide();

$("#viewByOrg").change(function () {
$(".visibleOnLoad").show();
$(".hiddenOnLoad").hide();
});

$("#viewByProduct").change(function () {
$(".visibleOnLoad").hide();
$(".hiddenOnLoad").show();
});
});



Here's the part of the XHTML that it affects. Apologies if it's not very clean, but the whole page does validate as XHTML 1.0 Strict:




<tr>
<td>View by:</td>
<td>
<p>
<input type="radio" name="viewBy" id="viewByOrg" value="organisation" checked="checked"/>
Organisation
</p>
<p>
<input type="radio" name="viewBy" id="viewByProduct" value="product"/>
Product
</p>
</td>
</tr>

<tr class="visibleOnLoad">
<td>Organisation:</td>
<td>
<select name="organisation" id="organisation" multiple="multiple" size="10">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
</td>
</tr>

<tr class="hiddenOnLoad">
<td>Product:</td>
<td>
<select name="product" id="product" multiple="multiple" size="10">
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
</td>
</tr>



If anyone has any ideas why this is happening and how to fix it, they would be very much appreciated!


Source: Tips4all

16 comments:

  1. Try using .click instead of .change.

    ReplyDelete
  2. The problem with using the click event instead of change is you get the event if the same radio box is selected (i.e. hasn't actually changed). This can be filtered out if you check that the new value is different than the old. I find this a little annoying.

    If you use the change event, you may notice that it will recognize the change after you click on any other element in IE. If you call blur() in the click event, it'll cause the change event to fire (only if the radio boxes actually have a changed).

    Here's how I'm doing it:

    // This is the hack for IE
    if ($.browser.msie) {
    $("#viewByOrg").click(function() {
    this.blur();
    this.focus();
    });
    }

    $("#viewByOrg").change(function() {
    // Do stuff here
    });


    Now you can use the change event like normal.

    Edit: Added a call to focus() to prevent accessibility issues (see Bobby's comment below).

    ReplyDelete
  3. Have you tried IE's onpropertychange event? I dont know if it makes a difference but it's probably worth a try. IE does not trigger the change event when values are updated via JS code but perhaps onpropertychange would work in this instance.

    $("#viewByOrg").bind($.browser.msie? 'propertychange': 'change', function(e) {
    e.preventDefault(); // Your code here
    });

    ReplyDelete
  4. This should work too:

    $(document).ready(function(){
    $(".hiddenOnLoad").hide();
    $("#viewByOrg, #viewByProduct").bind(($.browser.msie ? "click" : "change"), function () {
    $(".visibleOnLoad").show();
    $(".hiddenOnLoad").hide();
    });
    });


    Thanks Pier. This was very helpful.

    ReplyDelete
  5. In IE you must use the click event, in other browsers onchange.
    Your function could become

    $(document).ready(function(){
    $(".hiddenOnLoad").hide();
    var evt = $.browser.msie ? "click" : "change";
    $("#viewByOrg").bind(evt, function () {
    $(".visibleOnLoad").show();
    $(".hiddenOnLoad").hide();
    });

    $("#viewByProduct").bind(evt, function () {
    $(".visibleOnLoad").hide();
    $(".hiddenOnLoad").show();
    });
    });

    ReplyDelete
  6. add this plugin

    jQuery.fn.radioChange = function(newFn){
    this.bind(jQuery.browser.msie? "click" : "change", newFn);
    }


    then

    $(function(){
    $("radioBtnSelector").radioChange(function(){
    //do stuff
    });
    });

    ReplyDelete
  7. I'm pretty sure this is a known issue with IE. Adding a handler for the onclick event should fix the problem:

    $(document).ready(function(){

    $(".hiddenOnLoad").hide();

    $("#viewByOrg").change(function () {
    $(".visibleOnLoad").show();
    $(".hiddenOnLoad").hide();
    });

    $("#viewByOrg").click(function () {
    $(".visibleOnLoad").show();
    $(".hiddenOnLoad").hide();
    });

    $("#viewByProduct").change(function () {
    $(".visibleOnLoad").hide();
    $(".hiddenOnLoad").show();
    });

    $("#viewByProduct").click(function () {
    $(".visibleOnLoad").hide();
    $(".hiddenOnLoad").show();
    });
    });

    ReplyDelete
  8. This is a simple way to tell IE to fire the change event when the element is clicked:

    if($.browser.msie) {
    $("#viewByOrg").click(function() {
    $(this).change();
    });
    }


    You could expand this to something more generic to work with more form elements:

    if($.browser.msie) {
    $("input, select").click(function() {
    $(this).change();
    });
    $("input, textarea").keyup(function() {
    $(this).change();
    });
    }

    ReplyDelete
  9. In IE, force radio and checkboxes to trigger a "change" event:

    if($.browser.msie && $.browser.version < 8)
    $('input[type=radio],[type=checkbox]').live('click', function(){
    $(this).trigger('change');
    });

    ReplyDelete
  10. I had the same issue with input text.

    I changed:

    $("#myinput").change(function() { "alert('I changed')" });


    to

    $("#myinput").attr("onChange", "alert('I changed')");


    and everything is working fine for me!

    ReplyDelete
  11. as of jquery 1.6 this is no longer a problem.. not sure when it was fixed though.. Thank god for it though

    ReplyDelete
  12. If you change your jQuery version to 1.5.1, you won't have to adjust your code. Then IE9 wil listen just perfect to:

    $(SELECTOR).change(function() {
    // Shizzle
    });


    http://code.jquery.com/jquery-1.5.1.min.js

    ReplyDelete
  13. imo using click instead of change makes the ie behaviour be different.
    I'd rather emulate the change event behaviour using a timer (setTimout).

    something like (warning - notepad code):

    if ($.browser.msie) {
    var interval = 50;
    var changeHack = 'change-hac';
    var select = $("#viewByOrg");
    select.data(changeHack) = select.val();
    var checkVal=function() {
    var oldVal = select.data(changeHack);
    var newVal = select.val();
    if (oldVal !== newVal) {
    select.data(changeHack, newVal);
    select.trigger('change')
    }
    setTimeout(changeHack, interval);
    }
    setTimeout(changeHack, interval);
    }

    $("#viewByOrg").change(function() {
    // Do stuff here
    });

    ReplyDelete
  14. try this, it works for me

    $("#viewByOrg")
    .attr('onChange', $.browser.msie ? "$(this).data('onChange').apply(this)" : "")
    .change( function(){if(!$.browser.msie)$(this).data('onChange').apply(this)} )
    .data('onChange',function(){alert('put your codes here')});

    ReplyDelete
  15. This may help someone:
    Instead of starting with the form's id, target the select id and submit the form on change, like this:

    <form id='filterIt' action='' method='post'>
    <select id='val' name='val'>
    <option value='1'>One</option>
    <option value='2'>Two</option>
    <option value='6'>Six</option>
    </select>
    <input type="submit" value="go" />
    </form>


    ... and the jQuery:

    $('#val').change(function(){
    $('#filterIt').submit();
    });


    Howzit!?! (Obviously, the submit button is optional, in case javascript is disabled)

    ReplyDelete
  16. //global
    var prev_value = "";


    $(document).ready(function () {

    if (jQuery.browser.msie && $.browser.version < 8)
    $('input:not(:submit):not(:button):not(:hidden), select, textarea').bind("focus", function () {
    prev_value = $(this).val();

    }).bind("blur", function () {
    if($(this).val() != prev_value)
    has_changes = true;


    });
    }

    ReplyDelete