Reputation: 13
Trying to sort children div based on data attributes
The html code below is being generated by a CM and the data can be retrieved in any random order.
the html code is
<section class="box explore">
<div id="ProductContainer" class="row">
<div id="1232132" data-name="B" data-category="Category_A" class="explore-cell">
<h>B</h>
<p>Category_A</p>
</div>
<div id="123" data-name="A" data-category="Category_A" class="explore-cell">
<h>A</h>
<p>Category_A</p>
</div>
<div id="1232152351" data-name="C" data-category="Category_A" class="explore-cell">
<h>C</h>
<p>Category_A</p>
</div>
<div id="12342341" data-name="E" data-category="Category_B" class="explore-cell">
<h>E</h>
<p>Category_B</p>
</div>
<div id="1325321" data-name="D" data-category="Category_B" class="explore-cell">
<h>D</h>
<p>Category_B</p>
</div>
</div>
java
$('div').sort(function (a, b) {
var contentA = $(a).attr('data-name');
var contentB = $(b).attr('data-name');
return (contentA < contentB) ? -1 : (contentA > contentB) ? 1 : 0;
})
Jsfiddle http://jsfiddle.net/w8gkshue/
if someone can point me in the right direct on how to best sort either by Product Name or Category.
Updated hope this gives better explination
Upvotes: 0
Views: 903
Reputation: 10849
Why choose to sort by category or by name when you can sort by both?
I tried to write a generic multisort function generator, which should also work with the native array sort function.
A function that generates the multisort, it takes two parameters.
Here it is
function getMultisortFn(columns, provideColumnData) {
return function (a, b) {
for (var i = 0, l = columns.length; i < l; i++) {
var column = columns[i];
var aColumnData = provideColumnData[column.name](a, column.name);
var bColumnData = provideColumnData[column.name](b, column.name);
if (aColumnData !== bColumnData) {
if (column.asc) {
return String.prototype.localeCompare.call(aColumnData, bColumnData);
}
return String.prototype.localeCompare.call(bColumnData, aColumnData);
}
}
};
}
Now this is the part where you actually use the multisort generated
function retrieveDataAttribute(item, attribute) {
return $(item).data(attribute);
}
var $container = $('#ProductContainer');
var $products = $container.find('div');
var multisort = getMultisortFn([{
name: 'category',
asc: false
}, {
name: 'name',
asc: true
}], {
name: retrieveDataAttribute,
category: retrieveDataAttribute
});
$products.sort(multisort);
And finally the DOM manipulation to apply the new order
$products.detach().appendTo($container);
EDIT thanks to plalx:
$container.detach().append($products).appendTo('section.box.explore');
Upvotes: 0
Reputation: 236
You can use .sort method like this
var $wrapper = $('#ProductContainer');
$wrapper.find('.explore-cell').sort(function (a, b) {
return a.getAttribute('data-name') > b.getAttribute('data-name');
})
.appendTo( $wrapper );
But I don't sure about the cross browsing support
Upvotes: 1
Reputation: 1476
Calling only sort on them won't actually visually change the DOM, it just returns a sorted collection. So basically you just need to get the collection, sort it, then return it. Something like this should work:
$('#ProductContainer > div').detach().sort(function (a, b) {
var contentA = $(a).data('name');
var contentB = $(b).data('name');
return (contentA < contentB) ? -1 : (contentA > contentB) ? 1 : 0;
}).appendTo('#ProductContainer');
You'll want to make sure that you use the detach() method and not remove(), as detach() will retain all of the data and events associated with the collection items.
Upvotes: 0
Reputation: 43718
EDIT: I missed the jQuery tag... leaving the answer still.
var productCt = document.getElementById('ProductContainer'),
reInsertProductCt = tempRemove(productCt);
[].slice.call(productCt.children)
.sort(function (a, b) {
var aName = a.dataset.name,
bName = b.dataset.name;
return aName < bName? -1 : +(aName > bName);
})
.forEach(productCt.appendChild.bind(productCt));
reInsertProductCt();
function tempRemove(el) {
var parent = el.parentNode,
nextSibling = el.nextSibling;
parent.removeChild(el);
return function () {
if (nextSibling) parent.insertBefore(el, nextSibling);
else parent.appendChild(el);
};
}
<div id="ProductContainer" class="row">
<div id="1232132" data-name="B" data-category="Category_A" class="explore-cell">
<h>TEST NAME B</h>
<p>TEST</p>
</div>
<div id="123" data-name="A" data-category="Category_A" class="explore-cell">
<h>TEST NAME A</h>
<p>TEST</p>
</div>
<div id="1232152351" data-name="C" data-category="Category_A" class="explore-cell">
<h>TEST NAME C</h>
<p>TEST</p>
</div>
<div id="12342341" data-name="E" data-category="Category_B" class="explore-cell">
<h>TEST NAME E</h>
<p>TEST</p>
</div>
<div id="1325321" data-name="D" data-category="Category_B" class="explore-cell">
<h>TEST NAME D</h>
<p>TEST</p>
</div>
</div>
Upvotes: 1