Как отсортировать таблицу и повторно сгенерировать ее с помощью чистого JavaScript

#javascript #sorting #html-table

#javascript #сортировка #html-таблица

Вопрос:

Мне нужно отсортировать таблицу по имени. Для сортировки я использую функцию

 function sortArray(index) {
  let arr = [];
  rows.forEach( elem => {
    arr.push(elem.children[index].textContent); 
  })
  let sort = arr.sort( (a, b) => {
    if ( a > b) {
      return 1;
    }
    if (a < b) {
      return -1;
    }
    return 0;
  });
  console.log(sort);
  return sort;
  }
  

но я не знаю, как перерисовать таблицу. Таблицу я создаю из файла JSON динамически. Для того, чтобы начать сортировку, вам нужно нажать на название поля, после чего должна отобразиться уже отсортированная таблица.

 const buildHeader = data =>
  Object.keys(data)
    .map(k => `<th>${k}</th>`)
    .join("");
const buildRow = data =>
  Object.keys(data)
    .map(k => `<td>${data[k]}</td>`)
    .join("");
let element = document.querySelector(".people");

function showPeople(people) {
  let table = document.createElement("table");
  table.classList.add("people__table");
  let thead = document.createElement("thead");
  thead.innerHTML = `<tr class="head">${buildHeader(people[0])}</tr>`;
  table.appendChild(thead);
  let tbody = document.createElement("tbody");
  tbody.innerHTML = people
    .map(p => `<tr class="person">${buildRow(p)}</tr>`)
    .join("");
  table.appendChild(tbody);
  element.appendChild(table);
}

const customPeople = data =>
  data.map((p, i) => {
    return {
      name: p.name,
      sex: p.sex,
      born: p.born,
      died: p.died,
      age: p.died - p.born,
      mother: p.mother,
      father: p.father,
    };
  });

showPeople(customPeople(ANCESTRY_FILE));
  

Комментарии:

1. Если вы для начала создаете таблицу динамически из JSON, нельзя ли повторить этот процесс с отсортированными данными?

2.в стороне: этот подход работает, но innerHTML на самом деле не нужен. HTMLTableElement оснащен такими методами создания таблиц, как createTHead insertRow и т.д. Аналогично HtmlTableRow содержит такие методы, как insertCell , deleteCell и т.д.

3. @Lewis Это, конечно, возможно, но как сделать так, чтобы эти данные сортировались щелчками по названиям полей

Ответ №1:

Что-то вроде этой sortTable функции выполнило бы эту работу:

 function sortTable(tbody, index, ascending) {
    Array.prototype.slice.call(tbody.children).sort(
        (tr1, tr2) => tr1.children[index].textContent.localeCompare(tr2.children[index].textContent) * (ascending ? 1 : -1)
        ).forEach(tr => tbody.appendChild(tr));
    }

// demonstration
(function(){
    const thead_tr = document.getElementById('thdtr');
    const tbody = document.getElementById('tbd');
        
    function makeCell() {
        const td = document.createElement('td');
        td.appendChild(document.createTextNode(Math.round(Math.random() * 999999999).toString(36)));
        return td;
        }

    function makeRow() {
        const tr = document.createElement('tr');
        for(let i = 0; i < thead_tr.children.length; i  ) tr.appendChild(makeCell());
        return tr;
        }
    
    // adds click-to-sort functionality
    Array.prototype.forEach.call(thead_tr.children, (th, index) => {
        let asc_toggle = false; // false will start off in ascending order
        th.addEventListener('click', event => sortTable(tbody, index, asc_toggle = !asc_toggle));
        });
    
    // fills the table with random alphanumeric data
    for(let i = 0; i < 100; i  ) tbody.appendChild(makeRow());
    }());  
 <table>
    <thead>
        <tr id="thdtr">
            <th>col 1</th>
            <th>col 2</th>
            <th>col 3</th>
        </tr>
    </thead>
    <tbody id="tbd">
    </tbody>
<table>  

Моя sortTable функция — это универсальная функция сортировки таблиц на месте, которая должна работать с любой таблицей. Он принимает 3 параметра:

  1. tbody DOMElement — Ссылка либо на tbody элемент, либо на сам table элемент, в зависимости от того, что содержит tr элементы (строки).
  2. index Number — Индекс столбца для сортировки по (начинается с 0 ).
  3. ascending Boolean — Является ли порядок возрастающим ( true ) или убывающим ( false )

Пример использования для использования с вашим текущим кодом:

sortTable(document.querySelector('.people__table tbody'), 0, true);

Ответ №2:

Вы могли бы повторно отправить строки в тело таблиц:

  const body = document querySelector(".people__table > tbody");

 for(const el of sort)
   body.appendChild(el);
  

Или вы просто сортируете данные и повторно создаете всю таблицу.

Комментарии:

1. Это, конечно, возможно, но как сделать так, чтобы эти данные сортировались щелчками по названиям полей. Используя способ сортировки, запустили файл JSON.

Ответ №3:

Пожалуйста, найдите пример ниже:

 let data = generateData();

let columns = [
  {
    name: "id",
    callback: function() {
      flags.id *= -1;
      doSortInt("id", flags.id);
    }
  },
  {
    name: "name",
    callback: function() {
      flags.name *= -1;
      doSortStrings("name", flags.name);
    }
  },
  {
    name: "age",
    callback: function() {
      flags.age *= -1;
      doSortInt("age", flags.age);
    }
  }
];

var flags = {
  id: -1,
  name: -1,
  age: -1
};

createBasicTable(columns);

populateDataToTable(data);

function doSortInt(prop, flag) {
  data.sort(function(a, b) {
    return flag * (b[prop] - a[prop]);
  });
  populateDataToTable(data);
}

function doSortStrings(prop, flag) {
  data.sort(function(a, b) {
    return flag * (""   a[prop]).localeCompare(b[prop]);
  });
  populateDataToTable(data);
}

/**
 * This function is used to fill in the table with data from array
 */
function populateDataToTable(data) {
  let tableBody = document.querySelector("#table-body");
  // remove all childs
  while (tableBody.firstChild) {
    tableBody.removeChild(tableBody.firstChild);
  }

  // add new data
  data.forEach(function(el) {
    let tr = document.createElement("tr");

    let th1 = document.createElement("th");
    th1.innerHTML = el.id;
    tr.appendChild(th1);

    let th2 = document.createElement("th");
    th2.innerHTML = el.name;
    tr.appendChild(th2);

    let th3 = document.createElement("th");
    th3.innerHTML = el.age;
    tr.appendChild(th3);

    tableBody.appendChild(tr);
  });
}

/**
 * This function is used to create a basic empty table
 */
function createBasicTable(columns) {
  let element = document.querySelector("#table-container");
  let table = document.createElement("table");
  table.classList.add("people__table");
  let thead = document.createElement("thead");

  let tr = document.createElement("tr");

  columns.forEach(function(col) {
    let th = document.createElement("th");
    th.classList.add("head");
    th.innerHTML = col.name;
    th.addEventListener("click", col.callback);
    // add listener here
    tr.appendChild(th);
  });
  thead.appendChild(tr);
  table.appendChild(thead);

  let tbody = document.createElement("tbody");
  tbody.id = "table-body";
  table.appendChild(tbody);
  element.appendChild(table);
}

/**
 * This function is used to generate some data for the table
 */
function generateData() {
  let data = [];
  for (var i = 0; i < 100; i  ) {
    let obj = {
      id: i,
      name: "Name_"   (i   1),
      age: 30   i * 2
    };
    data.push(obj);
  }

  return data;
}  
 <!DOCTYPE html>
<html class="no-js">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title></title>
    <meta name="description" content="" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>

    <div id="table-container"></div>
  </body>
</html>  

Основными моментами являются:

В массиве определений столбцов у вас есть обратные вызовы для каждого заголовка столбца. Затем вы вызываете функцию

 createBasicTable
  

который создает пустую таблицу без данных. И в этой функции вы регистрируете обратные вызовы заголовков столбцов. Тогда у вас есть функция

 populateDataToTable
  

который принимает массив в качестве параметра и использует этот массив для построения строк таблицы.
Наконец, в ваших обратных вызовах вам просто нужно правильно отсортировать массив данных и обновить содержимое таблицы с помощью функции:

 populateDataToTable
  

p.s. Код не является совершенным, но он должен по крайней мере дать вам подсказку, как реализовать эту функциональность.
Я постараюсь улучшить код завтра.

Комментарии:

1. Если вы посмотрите на мой ответ, вы должны быть в состоянии увидеть, что решение этой проблемы совсем не очень сложное и не требует полного пересмотра алгоритма, используемого для генерации таблицы.