mazedlx mazedlx - 19 days ago 4
Javascript Question

Different jQuery UI behavior in different browsers

I have a very simple calendar. When clicking any date a jQuery dialog gets opened, the user clicks a button, the dialog closes, the clicked button's value gets appended to the clicked element and after that all clicked elements get saved to an array.

I have created a JSBin.

html:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<a href="#" id="2016-11-01" class="cal_clean_active">Click me</a>
<div id="dialog"></div>
<link href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</body>
</html>


js:

$('.cal_clean_active').click(function(e) {
var that = $(this);
var dates = new Array();

that.toggleClass('clicked');

$('#dialog').dialog({
resizable: false,
height: "auto",
width: "auto",
modal: true,
buttons: {
"Vormittags (bis 12:00 Uhr)": function() {
that.attr('slot','vormittags');
console.log(that.attr('slot'));
$(this).dialog('close');
}
},
beforeClose: function() {
$('.clicked').each(function(i, val) {
dates.push(val.id + '|' + val.slot);
});
console.log(dates);
}
});
});


In Chrome everything works as expected (Console output is
2016-11-01|vormittags
) in every other tested Browser (Firefox, Edge, IE) the console output is
2016-11-01|undefined
. Any help would be appreciated.

Answer

The problem is that slot is not a standard attribute for an element. In most browsers, it is hence not included in the standard properties of an element (like element.value or element.id). Chrome seems to handle this situation differently than the other browsers.

Two bad solutions

A solution would be to change:

dates.push(val.id + '|' + val.slot);

to

dates.push(val.id + '|' + $(val).attr('slot'));`. 

Another - plain javascript - solution could be to use the javascript getAttribute() method. This would work because in the jQuery source code custom attributes are set with this line:

elem.setAttribute( name, value + "" ); //from the jQuery source code

Thus making it possible to also read them with element.getAttribute(). Your line would then look like this:

dates.push(val.id + '|' + val.getAttribute("slot"));

The better solution

This might all work, but it still is not considered good code. In your code the attribute slot is used to store data. From the .data() jQuery docs (see this answer):

Store arbitrary data associated with the specified element. Returns the value that was set.

$.attr() on the contrary is used to manipulate attributes, like id, value or type. The clean way of solving this problem would be:

$('.cal_clean_active').click(function(e) {
  var that = $(this); 
  var dates = new Array();

  that.toggleClass('clicked');

  $('#dialog').dialog({
    resizable: false,
    height: "auto",
    width: "auto",
    modal: true,
    buttons: {
      "Vormittags (bis 12:00 Uhr)": function() {
        that.data('slot','vormittags'); //Not the use of data
        console.log(that.data('slot'));
        $(this).dialog('close');
      }
    },
    beforeClose: function() {
      $('.clicked').each(function(i, val) { 
        dates.push(val.id + '|' + $(val).data("slot")); //Also note it here
      });
        console.log(dates);
    }
  });
});