0

i'm building a dynamic table which i also need to sort, and the arrows to go accordingly with the values (ascending or descending if the sort is happening) if the values are ascending the arrow will always be up, if the values are descending the arrow is down, but also to toggle when clicking the same th and when clicking on another element the arrow should be accordingly with the sorting status. i've tried something here, but it's not working as it should.

many thanks in advance if you guys can help me with that

https://jsfiddle.net/947xkevd/

const API = 'https://raw.githubusercontent.com/alex-cenusa/movies/master/movies.json';

async function getData() {
  try {
    let response = await fetch(API);
    if (response.status == 200) {
      let data = await response.json();
      return data;
    } else {
      throw new Error(response.status);
    }
  } catch (error) {
    console.log(error);
  }
}

getData().then((data) => {
  const KEY = data.data.key.forEach((key) => {
    const LEGEND_WRAPPER = document.querySelector('.color-code-wrapper');
    const UNIT_TYPE = key.type;
    const KEY_BTN = document.createElement('button');
    KEY_BTN.innerText = UNIT_TYPE;
    const KEY_BTN_COLOR = key.color;
    KEY_BTN.style.backgroundColor = KEY_BTN_COLOR;
    LEGEND_WRAPPER.appendChild(KEY_BTN);
  });

  const TABLE_WRAPPER = document.querySelector('.table-wrapper');

  let col = [];
  for (let i = 0; i < data.data.movies.length; i++) {
    for (let key in data.data.movies[i]) {
      if (col.indexOf(key) === -1) {
        col.push(key);
      }
    }
  }
  let button_style = {
    "Comedy": "blue-button",
    "Thriller": "pink-button",
    "Alternative": "green-button",
    "Documentary": "red-button"
  }

  function mergeObjectValues(key, obj, tablecell) {
    let merge_string = [];
    let button;
    for (let i = 0; i < obj.length; i++) {
      if (merge_string.indexOf(obj[i][key]) == -1) {
        merge_string.push(obj[i][key]);
        if (key == 'type') {
          button = document.createElement('button');
          button.classList.add(button_style[obj[i][key]]);
          button.innerHTML = obj[i][key];
          tablecell.append(button);
        } else {
          merge_string.push(obj[i][key]);
          tablecell.innerHTML = obj[i][key];
        }
      }
    }
    return tablecell;
  }

  const table = document.createElement('table');
  let tr = table.insertRow(-1); // table row.

  for (let i = 0; i < col.length; i++) {
    let th = document.createElement('th'); // table header.
    th.setAttribute('class', 'sort-cta');
    th.innerHTML = col[i];
    tr.appendChild(th);

    const getCellValue = (tr, idx) => tr.children[idx].innerText || tr.children[idx].textContent;
    const comparer = (idx, asc) => (a, b) =>
      ((v1, v2) => (v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)))(
        getCellValue(asc ? a : b, idx),
        getCellValue(asc ? b : a, idx)
      );

    th.addEventListener('click', () => {
      sort();
    });

    function sort() {
      const table = th.closest('table');
      Array.from(table.querySelectorAll('tr:nth-child(n+2)'))
        .sort(comparer(Array.from(th.parentNode.children).indexOf(th), (this.asc = !this.asc)))
        .forEach((tr) => table.appendChild(tr));
    }
  }
  let col_key = {
    "Type/Use": "type",
    "Rental": "name"
  }
  for (let i = 0; i < data.data.movies.length; i++) {
    tr = table.insertRow(-1);

    for (let j = 0; j < col.length; j++) {
      let tabCell = tr.insertCell(-1);
      var tablecontent = data.data.movies[i][col[j]];

//          console.log(col);
//          console.log(tablecontent instanceof Array);
      if (tablecontent instanceof Array) {
        tabCell = mergeObjectValues(col_key[col[j]], tablecontent, tabCell);
      } else {
        tabCell.innerHTML = tablecontent;
      }

    }
  }

  TABLE_WRAPPER.appendChild(table);
  const sorLnk = document.querySelectorAll('.sort-cta');
  sorLnk.forEach((item) => {
    item.addEventListener('click', () => {
      [...item.parentElement.children].forEach((sib) => {
        sib.classList.remove('down');
        item.classList.add('down');
      });
    });
  });
});
.color-code-wrapper {
  display: flex;
  justify-content: space-around;
  align-items: center;
  max-width: 400px;
}

.title {
  font-weight: 600;
}

button {
  border: none;
  border-radius: 30px;
  padding: 4px 10px;
  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
  color: #fff;
  font-weight: 600;
}

table {
  width: 100%;
  margin: 32px 0;
}

tr {
  text-align: left;
  border-bottom: 1px solid #dddddd;
}

tr:first-of-type {
  border-bottom: 1px solid #333;
}

th {
  padding: 8px 0;
}

td {
  padding: 8px 0;
  font-size: 1.4rem;
}

.blue-button {
  background-color: rgb(64, 0, 255);
}

.pink-button {
  background-color: rgb(255, 0, 191);
}

.red-button {
  background-color: rgb(255, 0, 0);
}

.green-button {
  background-color: rgb(0, 255, 64);
}

.sort-cta {
  cursor: pointer;
  border: none;
  text-transform: capitalize;
  background-color: transparent;
}

.sort-cta:after {
  content: '\25b2';
  margin: 0 4px;
  font-size: 12px;
}

.sort-cta.down:after {
  content: '\25BC';
}


}
<div class="available-movies-component">
  <div class="color-code-wrapper">
    <span class="title">Key</span>
  </div>

  <div class="table-wrapper">

  </div>
</div>

2
  • What exactly is not working? Please be specific and give a step by step way to reproduce Commented Jun 26, 2020 at 11:57
  • what i want to achieve, is for every table header option, when i first click it, the data to be sort ascending(arrow up), and to be descending (down) only if i toggle the same option. if i click the title option for the first time the data will be ascending, then if i click the unit option the data will be ascending. now for example, if i'm clicking the tile option the data will be ascending but the arrow is down. Commented Jun 26, 2020 at 13:55

2 Answers 2

0

See my answer here: Select and sort a column in a table using Javascript, or here: Position table rows according to their dataset value.
You can add, change, and remove arrows with css(search for syntax).

Sign up to request clarification or add additional context in comments.

2 Comments

the sorting is working, the behaviour of the arrow is not working accordingly with the sorting
I see you have "up". What about "down"? When col th clicked: set "up"|"down" or toggle if already has "up"|"down", and remove both from siblings. Hope this helps.
0

I found some problems in this function. I fixed it.

sorLnk.forEach((item) => {
    item.addEventListener('click', () => {
        [...item.parentElement.children].forEach((sib) => {
            if (sib != item)
                // here we should check the sibling not to be the item itself
                sib.classList.remove('down');
        });
        // and here we toggle the 'down' class
        if (item.classList.contains('down')) {
            item.classList.remove('down');
        } else {
            item.classList.add('down');
        }
    });
});

2 Comments

tnx for your time, but this doesn't seems to be working..
it works for me! clean your cache and check again. check it in jsfiddle

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.