What is the easiest way to sort DOM elements using pure JavaScript?

1

How can I sort elements in the DOM using pure JavaScript , to be clearer, we assume that we have a static product page, and the products have a field to sort by price.

body {
    text-align: center
}
select {
    border: 0;
    font-family: sans-serif !important;
    padding: 4px;
    text-transform: uppercase;
    margin-bottom: 10px;
}
.clearfix {
    overflow: auto;
}
.produtos {
    display: block;
    margin: 0 auto;
    width: 90%;
}
.produtos .item {
    float: left;
    margin-right: 1%;
    width: 24%;
}
.produtos .item:nth-child(4n+0) {
    margin-right: 0;
}
.produtos .item h2 {
    font-family: sans-serif;
    font-size: 1.5em;
    margin: 0;
    padding: 0;
}
.produtos .item h3 {
    font-family: sans-serif;
    font-size: 1em;
    font-weight: 300;
}
<select>
    <option>Ordenar por:</option>
    <option value="maior_preco">Maior Preço</option>
    <option value="menor_preco">Menor Preço</option>
</select>

<div class="produtos clearfix">
    <div class="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto04</h2><h3>R$1.564,00</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto07</h2><h3>R$322,00</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto01</h2><h3>R$10,99</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto03</h2><h3>R$153,99</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto06</h2><h3>R$2,00</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto08</h2><h3>R$500,00</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150"/><h2>Produto05</h2><h3>R$2.999,99</h3></div><divclass="item">
        <img src="http://via.placeholder.com/300x150" />
        <h2>Produto 02</h2>
        <h3>R$ 768,99</h3>
    </div>
</div>
    
asked by anonymous 04.01.2018 / 12:48

2 answers

1

Assuming you have a built-in array of products that are displayed on the page, you can use the sort to apply an order by any criteria you want. This function receives a comparison function with the rules of comparison between each element.

Considering products with the following structure:

{
    imagem: string,
    nome: string,
    preco: double
}

We can order from highest price to lowest with:

produtos.sort(function(a,b){
  if (a.preco > b.preco) {
    return -1;
  }
  else if (b.preco > a.preco) {
    return 1;
  }
  else {
    return 0;
  }
});

Remembering that sort receives as a parameter the 2 elements to compare, in this example a and b , and returns:

  • < 0 if a is to stay before b
  • > 0 if a is to stay after b
  • 0 keeps both in the order they are

Another much simpler and more compact way of doing the same is:

produtos.sort((a,b) => b.preco - a.preco);

You not only get the returns through subtraction just as you use a Arrow Function instead of a normal function. And for ordering the lowest price simply reverse the logic of comparison:

produtos.sort((a,b) => a.preco - b.preco);

See your code working with this principle:

let produtos = [
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 04",
    "preco":1564
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 07",
    "preco":322
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 01",
    "preco":10.99
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 03",
    "preco":153.99
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 06",
    "preco":2
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 08",
    "preco":500
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 05",
    "preco":2999.99
  },
  {
    "imagem":"http://via.placeholder.com/300x150",
    "nome":"Produto 02",
    "preco":768.99
  }
];

function mostrarProdutos(){
  let novoHtml = "";
  
  for (let i = 0; i < produtos.length; ++i){
    novoHtml += '<div class="item">
                    <img src="${produtos[i].imagem}" />
                    <h2>${produtos[i].nome}</h2>
                    <h3>${produtos[i].preco.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })}</h3>
                </div>';
  }
  
  document.querySelector(".produtos").innerHTML = novoHtml;
}

const selectOrdenacao = document.querySelector("select");

selectOrdenacao.addEventListener("change", function(){
  if (selectOrdenacao.value == "maior_preco"){
    produtos.sort((a,b) => b.preco - a.preco);
  }
  else if (selectOrdenacao.value == "menor_preco"){
    produtos.sort((a,b) => a.preco - b.preco);
  }
  mostrarProdutos();
});

mostrarProdutos();
body {
    text-align: center
}
select {
    border: 0;
    font-family: sans-serif !important;
    padding: 4px;
    text-transform: uppercase;
    margin-bottom: 10px;
}
.clearfix {
    overflow: auto;
}
.produtos {
    display: block;
    margin: 0 auto;
    width: 90%;
}
.produtos .item {
    float: left;
    margin-right: 1%;
    width: 24%;
}
.produtos .item:nth-child(4n+0) {
    margin-right: 0;
}
.produtos .item h2 {
    font-family: sans-serif;
    font-size: 1.5em;
    margin: 0;
    padding: 0;
}
.produtos .item h3 {
    font-family: sans-serif;
    font-size: 1em;
    font-weight: 300;
}
<select>
    <option>Ordenar por:</option>
    <option value="maior_preco">Maior Preço</option>
    <option value="menor_preco">Menor Preço</option>
</select>

<div class="produtos clearfix">
    
</div>

The mostrarProdutos function constructs the whole html that the <div class="produtos clearfix"> had statically based on the array of products and applies it through the innerHTML property.

So in the change of <select> it is only necessary to change the order of the elements in the produtos array based on the chosen value and call the mostrarProdutos function again.

    
04.01.2018 / 13:48
1

Really sort is the easiest way, but to apply directly to DOM , without changing the structure, you need to apply a regular expression and format the value so that it can be handled in the function, eg ...

function ordenar() {

let op = document.getElementById("ord").value;
let itens = document.querySelectorAll('.item');
let itensNV = [];

function mpreco(a,b) {
     return parseFloat(a.preco.replace(/R\$|\.|\,|\s/g, "")) < parseFloat(b.preco.replace(/R\$|\.|\,|\s/g, "")) ? -1 : 1; }
               

function mapreco(a,b) {
     return parseInt(a.preco.replace(/R\$|\.|\,|\s/g, "")) > parseInt(b.preco.replace(/R\$|\.|\,|\s/g, "")) ? -1 : 1; }
              

for(let i = 0; i < itens.length; i++) {
	let content = {
		html : itens[i],
        preco : itens[i].children[2].textContent
	}
    itensNV.push(content);
}

switch(op) {
      case 'maior_preco':
			itensNV = itensNV.sort(mapreco);
      break;
      
      case 'menor_preco':
			itensNV = itensNV.sort(mpreco);
      break;
}

document.querySelector('.produtos').innerHTML = '';

for(let i = 0; i < itensNV.length; i++)
   document.querySelector('.produtos').appendChild(itensNV[i].html);

}
    body {
        text-align: center
    }
    select {
        border: 0;
        font-family: sans-serif !important;
        padding: 4px;
        text-transform: uppercase;
        margin-bottom: 10px;
    }
    .clearfix {
        overflow: auto;
    }
    .produtos {
        display: block;
        margin: 0 auto;
        width: 90%;
    }
    .produtos .item {
        float: left;
        margin-right: 1%;
        width: 24%;
    }
    .produtos .item:nth-child(4n+0) {
        margin-right: 0;
    }
    .produtos .item h2 {
        font-family: sans-serif;
        font-size: 1.5em;
        margin: 0;
        padding: 0;
    }
    .produtos .item h3 {
        font-family: sans-serif;
        font-size: 1em;
        font-weight: 300;
    }
<select onchange="ordenar()" id="ord">
        <option>Ordenar por:</option>
        <option value="maior_preco">Maior Preço</option>
        <option value="menor_preco">Menor Preço</option>
    </select>

    <div class="produtos clearfix">
        <div class="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto04</h2><h3>R$1.564,00</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto07</h2><h3>R$322,00</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto01</h2><h3>R$10,99</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto03</h2><h3>R$153,99</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto06</h2><h3>R$2,00</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto08</h2><h3>R$500,00</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150"/><h2>Produto05</h2><h3>R$2.999,99</h3></div><divclass="item">
            <img src="http://via.placeholder.com/300x150" />
            <h2>Produto 02</h2>
            <h3>R$ 768,99</h3>
        </div>
    </div>
    
04.01.2018 / 13:58