Help with Sorting Elements

Hi there,

I really hope you can help me with the following issue I faced and tried to solve more than a week time.

I’m building the UI of e-commerce website(personal project) and I have sorting options by price, name etc. So lets say I have an array with the elements and I need to sort them using their data-attribute(name) and apply alphabetical order to those elements. I attached the code I have which works fine but the problem is that each time I add new item I need to add it to javascript function as well. The idea is to create it with loop that will do that automatically and will be more reusable as I need to do 4 of them.

const filterZtoA = () => {
	const arr = [].slice.call(document.querySelectorAll('[data-name]'));
	const zToA = [];

	arr.forEach(item => {
		zToA.push(item.getAttribute('data-name'));
	})

	zToA.sort((a,b) => a < b);
	arr.forEach(el => {
		if(el.getAttribute('data-name') == zToA[0]){
			el.style.order = '0';
		}else if(el.getAttribute('data-name') == zToA[1]){
			el.style.order = '1';
		}
		else if(el.getAttribute('data-name') == zToA[2]){
			el.style.order = '2';
		}
		else if(el.getAttribute('data-name') == zToA[3]){
			el.style.order = '3';
		}
		else if(el.getAttribute('data-name') == zToA[4]){
			el.style.order = '4';
		}
	});
}

I would be really grateful if you can help me with that problem,

Thanks a lot!

OK: here is a way to do it based on what you have already. There are better ways to do this: at the very least, you can remove the duplication, but this maybe gives you an idea:

So if you make an array of all the elements - like what you’re doing with slice.call, but instead of just doing that, you can use Array.from.

Array.from takes an array-like thing and turns it into an array (natch), but it can also take a second argument, which is a mapping function, which will transform each element - what I want here is to create a set of objects that have both a name and a reference to the DOM element. So you can do (I’ve tried to make the names as verbose as possible here just for the example):

const dataNameElements = document.querySelectorAll('[data-name]');
const namedElements = Array.from(dataNameElements, function(element) {
  return { name: element.dataset.name.toLowerCase(), element: element };  
});

This gives you an array of objects, and each object has a name field and an element field (which is a reference to the DOM element).

Now you can do:

const sortedNamedElements = namedElements.sort((a, b) => a.name < b.name)

And then your array is in Z-A order, so:

sortedNamedElements.forEach((el, index) => el.element.style.order = index)

Hope that sorta makes sense. As I say, it is very rough, the code can be significantly improved.

1 Like

Massive thanks to DanCouper for the help above,

Slight issue I had is that as I was using really long strings as my data-attributes I’ve had to add small condition on the sort() function.

//  Function to sort them in Desc-Alphabetical order Z-A
const filterZtoA = () => {
	const products = Array.from(document.querySelectorAll('[data-name]'), function(product) { 
        return { name: product.dataset.name, element: product }
  	});
	const sortedProducts = products.sort((a, b) => a.name < b.name ? 1 : -1);
  
	sortedProducts.forEach((product, i) => product.element.style.order = i);
}

Really appreciate it, if you want to see live version of how it works, you can check my guthub repo here