I've got a custom jQuery script that takes in a target element and then restacks child card
elements into a number of columns. The script is useful for stacking cards dynamically when you don't know in advance how many cards your page will have. The script itself normally works great, however I've recently stumbled upon a problem I can't quite pin down.
I recently added polyfills from MDN for Array.prototype.includes and String.prototype.includes for Internet Explorer compatibility for another feature in my app. When I added those polyfills my stacking script stopped working in Internet Explorer 11.
Here is the stacking script:
function resizeColumns(layoutElem, ignoreRank, width) {
if(width === undefined) {
var colMin = 240;
} else {
var colMin = width;
};
var w = layoutElem.width();
var numCols = Math.floor(w / colMin);
if(numCols == 0) numCols = 1;
layoutElem.removeClass('cols-1 cols-2 cols-3 cols-4 cols-5 cols-6 cols-7 cols-8 cols-9 cols-10 cols-11 cols-12');
layoutElem.addClass('cols-' + numCols);
var cols = layoutElem.find('.col');
var cards = cols.find('.card');
var sortedCards = [];
cards.each(function(i) {
var rank;
if(!ignoreRank) {
rank = parseInt($(this).attr('rank'));
if(isNaN(rank)) rank = 1000000;
} else {
var o = parseInt($(this).attr('order'));
if(isNaN(o)) {
rank = i;
$(this).attr('order', i);
} else {
rank = o;
}
}
sortedCards.push({
rank: rank,
element: $(this)
});
});
sortedCards.sort(rankCompare);
var curCol = 0;
for(var i in sortedCards) {
var cardElem = sortedCards[i].element;
cardElem.appendTo($(cols[curCol]));
curCol++;
if(curCol >= numCols) curCol = 0;
}
// hide any additional columns
cols.each(function(i) {
if(i >= numCols) {
$(this).hide();
} else {
$(this).show();
}
});
function rankCompare(a, b) {
if (a.rank < b.rank)
return -1;
if (a.rank > b.rank)
return 1;
return 0;
}
}
When the script is called in IE 11 (with the polyfills added), I see the following error in the console:
Unable to get property 'appendTo' of undefined or null reference
I've created a jsFiddle that might be helpful for reproducing the problem. The fiddle includes the two polyfills. When I run it on Chrome for OS X it works fine, but on IE 11 it breaks. Unfortunately I don't have access to a Windows machine of my own, so my ability to debug the issue myself is limited. I rely on a remote colleague using screenshare for troubleshooting issues like this.
What I'd like to know is why the polyfills break my stacking script and how I can mitigate the problem. I need to polyfills for another feature. I'm running jQuery v1.12 on my production site, however I've tested the script with jQuery v2.12 (fiddle) as well as jQuery v3.0.0-beta1 (fiddle) with the same results. It seems like the polyfills are affecting something in the jQuery library.
Update with working polyfills
For what it's worth, I was able to modify my polyfills based off the linked question and the stacking script seems to be working again. Here is the code:
if (!String.prototype.includes) {
Object.defineProperty(String.prototype, "includes", {
enumerable: false,
writable: true,
value: function(search, start) {
'use strict';
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
}
});
}
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, "includes", {
enumerable: false,
writable: true,
value: function(searchElement /*, fromIndex*/ ) {
'use strict';
var O = Object(this);
var len = parseInt(O.length) || 0;
if (len === 0) {
return false;
}
var n = parseInt(arguments[1]) || 0;
var k;
if (n >= 0) {
k = n;
} else {
k = len + n;
if (k < 0) {k = 0;}
}
var currentElement;
while (k < len) {
currentElement = O[k];
if (searchElement === currentElement ||
(searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
return true;
}
k++;
}
return false;
}
});
}