Как отсортировать таблицу и заново сгенерировать ее с помощью чистого JavaScript - PullRequest
3 голосов
/ 13 марта 2019

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

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));

Ответы [ 3 ]

1 голос
/ 13 марта 2019

Примерно такая функция 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);

0 голосов
/ 14 марта 2019

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

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. Код не является префектом, но он должен по крайней мере дать вам подсказку, как реализовать эту функцию. Я постараюсь улучшить код завтра.

0 голосов
/ 13 марта 2019

Вы можете добавить строки в тело таблицы:

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

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

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

...