Sorting

Recipe 11.4 Sort columns

Sample:

Records

Filter

Country
Shipping
Sort by

Results

  1. Bambule (1998) Absolute Beginner
  2. Very proud of ya (1996) AFI
  3. All Hollows EP (1999) AFI
  4. Die große Palmöllüge (2020) Akne Kid Joe
  5. Suffer (1988) Bad Religion
  6. Age of Unreason (2019) Bad Religion
  7. Licensed to Ill (1986) Beastie Boys
  8. Paul's Boutique (1989) Beastie Boys
  9. Check Your Head (1992) Beastie Boys
  10. Ill Communication (1994) Beastie Boys

Code:

<style>
   strong {
    display: block;
  }

   .pagination ol {
    display: flex;
    list-style: none;
    gap: 0.5em;
    margin: 0;
    padding: 0;
  }

   .pagination a {
    align-items: center;
    aspect-ratio: 1;
    border: 1px solid;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    text-decoration: none;
    width: 2em;
  }

   .pagination a:is([aria-current="page"], :hover, :focus-visible) {
    background-color: #3c843f;
    color: #ffffff;
  }

   .visually-hidden {
    clip-path: inset(50%);
    height: 1px;
    overflow: hidden;
    position: absolute;
    white-space: nowrap;
    width: 1px;
  }
</style>

<h1>Records</h1>

<h2>Filter</h2>

<form role="form" aria-label="Filter" id="filter">
  <label for="artist">Artist</label>
  <select id="artist" name="artist">
    <option value="">All</option>
    <option>AFI</option>
    <option>Absolute Beginner</option>
    <option>Akne Kid Joe</option>
    <option>Bad Religion</option>
    <option>Beastie Boys</option>
    <option>Bilderbuch</option>
    <option>Billy Joel</option>
    <option>Bring me the Horizon</option>
    <option>Dead Kennedys</option>
    <option>Dendemann</option>
    <option>Der Nino aus Wien</option>
    <option>Dog Eat Dog</option>
    <option>Dr. Dre</option>
    <option>Eater</option>
    <option>Idles</option>
    <option>Minutemen</option>
    <option>PUP</option>
    <option>Rancid</option>
    <option>The Eradicator</option>
    <option>The Menzingers</option>
  </select>

  <fieldset>
    <legend>Country</legend>

    <input type="checkbox" name="country" id="country_at" value="at">
    <label for="country_at">Austria</label>

    <input type="checkbox" name="country" id="country_ca" value="ca">
    <label for="country_ca">Canada</label>

    <input type="checkbox" name="country" id="country_us" value="us">
    <label for="country_us">USA</label>

    <input type="checkbox" name="country" id="country_de" value="de">
    <label for="country_de">Germany</label>

    <input type="checkbox" name="country" id="country_uk" value="uk">
    <label for="country_uk">United Kingdom</label>
  </fieldset>

  <fieldset>
    <legend>Shipping</legend>

    <input type="radio" name="shipping" id="shipping_eu" value="eu">
    <label for="shipping_eu">Europe</label>

    <input type="radio" name="shipping" id="shipping_world" value="worldwide">
    <label for="shipping_world">Worldwide</label>

    <input type="radio" name="shipping" id="shipping_us" value="us">
    <label for="shipping_us">USA</label>
  </fieldset>

  <fieldset id="sorting">
    <legend>Sort by</legend>

    <div>
      <input type="radio" id="sorting_artist" name="sorting" checked value="artist">
      <label for="sorting_artist">Artist</label>
      <input type="radio" id="sorting_date" name="sorting" value="year">
      <label for="sorting_date">Date</label>
    </div>
  </fieldset>
  <div id="live-region-sorting" hidden>Sorted by [type]</div>

  <button>Search</button>
</form>

<div role="region" aria-labelledby="results_heading" id="results" tabindex="-1">
  <h2 id="results_heading">Results</h2>
  <div role="status" class="visually-hidden"></div>

  <ol>
    
      <li>
        <strong>Bambule (1998)</strong>
        Absolute Beginner
      </li>
    
      <li>
        <strong>Very proud of ya (1996)</strong>
        AFI
      </li>
    
      <li>
        <strong>All Hollows EP (1999)</strong>
        AFI
      </li>
    
      <li>
        <strong>Die große Palmöllüge (2020)</strong>
        Akne Kid Joe
      </li>
    
      <li>
        <strong>Suffer (1988)</strong>
        Bad Religion
      </li>
    
      <li>
        <strong>Age of Unreason (2019)</strong>
        Bad Religion
      </li>
    
      <li>
        <strong>Licensed to Ill (1986)</strong>
        Beastie Boys
      </li>
    
      <li>
        <strong>Paul&#39;s Boutique (1989)</strong>
        Beastie Boys
      </li>
    
      <li>
        <strong>Check Your Head (1992)</strong>
        Beastie Boys
      </li>
    
      <li>
        <strong>Ill Communication (1994)</strong>
        Beastie Boys
      </li>
    
  </ol>
</div>

<nav aria-label="Select page" class="pagination">
  <ol>
    <li>
      <a href="/filter.html/1" aria-current="page">1</a>
    </li>
    <li>
      <a href="/filter.html/2">2</a>
    </li>
    <li>
      <a href="/filter.html/3">3</a>
    </li>
    <li>
      <a href="/filter.html/4">4</a>
    </li>
  </ol>
</nav>

<script>
const form = document.getElementById("filter");
const results = document.getElementById("results");
const list = results.querySelector("ol");
const sorting = form.querySelector("#sorting");
const liveRegion = document.querySelector("[role='status']")
const sortingMessage = document.querySelector("#live-region-sorting");

let records,
filtered;

function finishQuery() {
  results.focus();
}

function showResults() {
  list.innerHTML = "";
console.log(filtered)
  for (let i = 0; i < filtered.length; i++) {
    const record = filtered[i];
    const item = document.createElement("li");
    const title = document.createElement("strong");
    title.textContent = `${record.title} (${record.year})`;
    item.append(title, record.artist);
    list.append(item);
  }
}

function filterForm(e) {
  e.preventDefault();

  const formData = new FormData(form);

  filtered = records.filter((record) => {
    const artist = formData.get("artist");
    const countries = formData.getAll("country");
    const shipping = formData.getAll("shipping");

    if (artist && record.artist !== artist) {
      console.log(1)
      return;
    }

    if (countries.length && !countries.includes(record.country)) {
      console.log(2)
      return;
    }

    if (shipping.length && !shipping.includes(record.shipping)) {
      console.log(3)
      return;
    }
      console.log(4)

    return true;
  });

  showResults();
  finishQuery();
}

async function getRecords() {
  const response = await fetch("/assets/data/records.json");
  return await response.json();
}

function sortRecords(type) {
  function compare(a,b) {
    let fieldA = a[type];
    let fieldB = b[type];

    if (typeof fieldA === 'string') {
      fieldA = fieldA.toLowerCase()
      fieldB = fieldB.toLowerCase()
    }
    
    if (fieldA < fieldB){
      return -1;
    }
    if (fieldA > fieldB){
      return 1;
    }
    return 0;
  }

  filtered.sort(compare);
}

getRecords().then((data) => {
  records = data;
  filtered = data;
  
  form.addEventListener("submit", filterForm);

sorting.addEventListener("change", (e) => {
  const type = e.target.value;
  sortRecords(type);
  showResults();
  liveRegion.textContent = sortingMessage.textContent.replace("[type]", type);
});
});

</script>