There is a well documented extension for Datatables that allows for the sorting of data which contains images.
This works well if all the entries have an alt tag.
In my case my data looks like this:
<tr class="tablebody tablebodyhover">
<td>Item1 description</td>
<td><img src='icon-tick.svg' alt='tick' width='16' height='16'/></td>
<td class="textcenter"></td>
</tr>
<tr class="tablebody tablebodyhover">
<td>Item2 description</td>
<td></td>
</tr>
<tr class="tablebody tablebodyhover">
<td>Item3 description</td>
<td></td>
</tr>
<tr class="tablebody tablebodyhover">
<td>Item4 description</td>
<td><img src='icon-tick.svg' alt='tick' width='16' height='16'/></td>
</tr>
As you can see from the HTML not every line has an image and as a result the extension fails to sort because it cannot match alt tag (as there isn't one).
The Datatables extension for sorting looks like this:
// sort by alt of image extension
$.extend($.fn.dataTableExt.oSort, {
"alt-string-pre": function ( a ) {
return a.match(/alt="(.*?)"/)[1].toLowerCase();
},
"alt-string-asc": function( a, b ) {
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
},
"alt-string-desc": function(a,b) {
return ((a < b) ? 1 : ((a > b) ? -1 : 0));
}
});
It relies on a regex to match the alt string.
Is it possible to modify the extension to allow for rows that have no alt tag and still sort accordingly.
I appreciate that one work around would be to add a dummy image to each line in the HTML but I am interested to find out whether this could be achieved without using dummy images to provide the missing alt tags?
EDIT:
The full working solution:
$.extend($.fn.dataTableExt.oSort, {
"alt-string-pre": function ( a ) {
return a.match(/alt="(.*?)"/)?.[1]?.toLowerCase() ?? '';
},
"alt-string-asc": function( a, b ) {
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
},
"alt-string-desc": function(a,b) {
return ((a < b) ? 1 : ((a > b) ? -1 : 0));
}
});
This now sorts by image alt even with no images present.
In the expression:
a.match(/alt="(.*?)"/)[1].toLowerCase();
if there is no match (no element with an alt
attribute), a null
is returned by the match method... resulting in:
null[1].toLowerCase();
which throws the error Cannot read properties of null (reading '1')
.
To avoid this, look for Optional Chaining to stop the chained execution on undefined
and null
and set a default value to be returned (like an empty string) using a Nullish coalescing operator (??
).
So that would be:
a.match(/alt="(.*?)"/)?.[1]?.toLowerCase() ?? '';