AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题 / 78535198
Accepted
Yaroslav Demchenko
Yaroslav Demchenko
Asked: 2024-05-26 20:01:31 +0800 CST2024-05-26 20:01:31 +0800 CST 2024-05-26 20:01:31 +0800 CST

尝试对表进行排序:类型错误:无法读取未定义的属性(读取“textContent”)

  • 772

我试图对表中的余额进行排序。但是有一个问题。我尝试用代码进行排序:

function sortTableByBalance() {
    const table = document.getElementById("myTable");
    const arr = Array.from(table.rows, row => [row, +row.cells[2].textContent]).slice(1);
    arr.sort(([,a], [,b]) => a - b);
    for (const [elem] of arr) {
        table.appendChild(elem);
    }
}

这是在另一个问题中向我建议的。但浏览器中的 javascript 控制台向我显示了错误:

Uncaught TypeError: Cannot read properties of undefined (reading 'textContent')

这个错误向我展示了这个阶段:

const sortBtnBalance = document.querySelector(".sort-balance-btn");
sortBtnBalance.addEventListener("click", sortTableByBalance);
function sortTableByBalance() {
  const table = document.getElementById("myTable");
  const tableRows = table.rows;
  const arrs = Array.from(tableRows, (row) => [
    row,
    +row.cells[3].textContent,
  ]).slice(1, -1);
}

我假设 js 抱怨列中存在空单元格,因为在显示这些相同行的单元格的 textContent 后,我​​使用切片删除了所有不必要的行。但我仍然不明白如何解决这个问题。

我的 tableRender 使用 JavaScript:

// дать нам новый массив объектов
const usrs = getUsers();

// основной контейнер для таблицы
const usersContainer = document.querySelector(
  ".users-list-section .users-group"
);

// статическая thead таблицы
function theadTemplate() {
  // создать элемент thead
  const thead = document.createElement("thead");
  // создать элемент tr
  const tr = document.createElement("tr");
  // создать элемент th1 и дать ему атрибуты
  const th1 = document.createElement("th");
  th1.setAttribute("scope", "col");
  th1.textContent = "#";

  /* reset sort btn */
  const resetSortBtn = document.createElement("button");
  resetSortBtn.setAttribute("type", "button");
  resetSortBtn.addEventListener("click", renderUsers);
  resetSortBtn.classList.add("btn", "btn-dark", "reset-sort-btn");

  const i0 = document.createElement("i");
  i0.classList.add("bi", "bi-arrow-clockwise", "reset-clockwise");

  resetSortBtn.appendChild(i0);
  th1.appendChild(resetSortBtn);

  // создать элемент th2 и дать ему атрибуты
  const th2 = document.createElement("th");
  th2.setAttribute("scope", "col");
  th2.textContent = "Name";
  // sort btn для сортировки юзеров по именам
  const sortBtnNames = document.createElement("button");
  sortBtnNames.setAttribute("type", "button");
  sortBtnNames.setAttribute("onclick", "namesSortHandler(1)");
  sortBtnNames.classList.add("btn", "btn-dark", "sort-names-btn");
  // иконка стрелка
  const i1 = document.createElement("i");
  i1.classList.add("bi", "bi-arrow-up", "sort-names-arrow");

  // добавить стрелку в кнопку и кнопку в th
  sortBtnNames.appendChild(i1);
  th2.appendChild(sortBtnNames);
  // создать элемент th3 и дать ему атрибуты
  const th3 = document.createElement("th");
  th3.setAttribute("scope", "col");
  th3.textContent = "Email";
  // создать элемент th4 и дать ему атрибуты
  const th4 = document.createElement("th");
  th4.setAttribute("scope", "col");
  th4.textContent = "Balance";

  // sort btn для сортировки юзеров по балансу
  const sortBtnBalance = document.createElement("button");
  sortBtnBalance.setAttribute("type", "button");
  sortBtnBalance.classList.add("btn", "btn-dark", "sort-balance-btn");
  // иконка стрелка
  const i2 = document.createElement("i");
  i2.classList.add("bi", "bi-arrow-up", "sort-balance-arrow");

  // добавить стрелку в кнопку и кнопку в th
  sortBtnBalance.appendChild(i2);
  th4.appendChild(sortBtnBalance);

  // добавить детей в родителей
  tr.appendChild(th1);
  tr.appendChild(th2);
  tr.appendChild(th3);
  tr.appendChild(th4);
  thead.appendChild(tr);

  // вернуть полноценно собранный thead
  return thead;
}
// полноценно собранный thead из функции записать в переменную.
const thead = theadTemplate();

// tbody таблицы (основное тело, куда будут писаться пользователи.)
function tbodyTemplate({
  _id,
  name,
  email,
  isActive,
  balance,
  number,
  wiki,
} = {}) {
  // создать элемент tbody
  const tbody = document.createElement("tbody");
  // создать элемент tr
  const tr = document.createElement("tr");
  // создать элемент th и дать ему классы и стили
  const th = document.createElement("th");
  th.classList.add("table-secondary");

  th.style.color = "black";
  th.style.fontWeight = "bold";
  th.setAttribute("scope", "row");
  th.textContent = number;

  // создать элемент tdName и дать ему классы и стили
  const tdName = document.createElement("td");
  tdName.classList.add("table-secondary");
  // nameLink имя с ссылкой на статью в wiki каждого юзера
  const nameLink = document.createElement("a");
  nameLink.setAttribute("href", wiki);
  nameLink.setAttribute("target", "_blank");
  nameLink.style.color = "black";
  nameLink.style.fontWeight = "bold";
  nameLink.textContent = name;

  // создать элемент tdEmail и дать ему классы и стили
  const tdEmail = document.createElement("td");
  tdEmail.classList.add("table-secondary");
  tdEmail.style.color = "black";
  tdEmail.style.fontWeight = "bold";
  tdEmail.textContent = email;

  // создать элемент tdBalance и дать ему классы и стили
  const tdBalance = document.createElement("td");
  tdBalance.classList.add("table-secondary", "tdbalance");
  tdBalance.style.color = "black";
  tdBalance.style.fontWeight = "bold";
  tdBalance.textContent = Number(balance);

  // Добавляем детей в родителей, собираем конструкцию
  tr.appendChild(th);
  tdName.appendChild(nameLink);
  tr.appendChild(tdName);
  tr.appendChild(tdEmail);
  tr.appendChild(tdBalance);
  tbody.appendChild(tr);

  // вернуть собранный tbody
  return tbody;
}

// Каркас итогового общего баланса юзеров
function totalBalanceTemplate(balance) {
  // В balance мы передаём массив балансов всех юзеров из функции renderUsers
  // Просуммировать балансы всех юзеров
  const result = balance.reduce((acc, curr) => {
    let result;
    acc = acc + curr;
    result = acc;
    return result;
  }, 0);

  // элемент футера для таблицы
  const tfoot = document.createElement("tfoot");

  // контейнер для строки таблицы
  const tr = document.createElement("tr");

  // сама строка таблицы, здесь примечателен аттрибут colspan
  // в текст контент записываем результат суммирования балансов юзеров с двумя знаками после запятой
  const td = document.createElement("td");
  td.setAttribute("colspan", "4");
  td.style.textAlign = "end";
  td.style.fontWeight = "bold";
  td.textContent = `Total balance: ${result.toFixed(2)}`;

  tr.appendChild(td);
  tfoot.appendChild(tr);

  // вернуть собранный tfoot
  return tfoot;
}

// table таблица и render users отображение в ней пользователей
function renderUsers(usersList) {
  // создать фрагмент
  const fragment = document.createDocumentFragment();
  // создать элемент таблицы и дать ей классы bootstrap
  const table = document.createElement("table", "users-table");
  table.setAttribute("id", "myTable");
  table.classList.add("table-dark", "table", "table-hover", "col");

  // важно создать тотал баланс именно вне foreach и записать его в таблицу так же вне
  // иначе тотал баланс у нас будет висеть после каждого пользователя
  let totalBalance;

  Object.values(usersList).forEach((user) => {
    // создать массив из балансов всех юзеров, записать в result
    let result = usersList.map((user) => Number(user.balance));
    // записать в переменную totalBalance функцию возвращающую каркас(template)
    // передать массив балансов в функцию totalBalanceTemplate
    totalBalance = totalBalanceTemplate(result);
    // здесь записываем тело таблицы в переменную, она возвращает каркас(template)
    // сюда уже передаём просто юзеров
    const tbody = tbodyTemplate(user);
    // добавляем элементы в таблицу
    table.appendChild(thead);
    table.appendChild(tbody);

    fragment.appendChild(table);
  });
  // последний элемент в таблицу, totalBalance
  table.appendChild(totalBalance);
  usersContainer.appendChild(fragment);

  return table;
}
renderUsers(usrs);

我的HTML:

<div class="users-wrapper active">
  <div class="users-list-section mt-5">
    <div class="container">
      <ul class="users-group">
        <table
          is="users-table"
          id="myTable"
          class="table-dark table table-hover col"
        >
          <tbody>
            <tr>
              <th
                class="table-secondary"
                scope="row"
                style="color: black; font-weight: bold;"
              >
                1
              </th>
              <td class="table-secondary">
                <a
                  href="https://en.wikipedia.org/wiki/H._P._Lovecraft"
                  target="_blank"
                  style="color: black; font-weight: bold;"
                >
                  Govard Lovecraft
                </a>
              </td>
              <td
                class="table-secondary"
                style="color: black; font-weight: bold;"
              >
                [email protected]
              </td>
              <td
                class="table-secondary tdbalance"
                style="color: black; font-weight: bold;"
              >
                2853.33
              </td>
            </tr>
          </tbody>
          <tbody>
            <tr>
              <th
                class="table-secondary"
                scope="row"
                style="color: black; font-weight: bold;"
              >
                2
              </th>
              <td class="table-secondary">
                <a
                  href="https://en.wikipedia.org/wiki/Yukio_Mishima"
                  target="_blank"
                  style="color: black; font-weight: bold;"
                >
                  Yukio Mishima
                </a>
              </td>
              <td
                class="table-secondary"
                style="color: black; font-weight: bold;"
              >
                [email protected]
              </td>
              <td
                class="table-secondary tdbalance"
                style="color: black; font-weight: bold;"
              >
                1464.63
              </td>
            </tr>
          </tbody>
          <tbody>
            <tr>
              <th
                class="table-secondary"
                scope="row"
                style="color: black; font-weight: bold;"
              >
                3
              </th>
              <td class="table-secondary">
                <a
                  href="https://en.wikipedia.org/wiki/Taras_Shevchenko"
                  target="_blank"
                  style="color: black; font-weight: bold;"
                >
                  Taras Shevchenko
                </a>
              </td>
              <td
                class="table-secondary"
                style="color: black; font-weight: bold;"
              >
                [email protected]
              </td>
              <td
                class="table-secondary tdbalance"
                style="color: black; font-weight: bold;"
              >
                3723.39
              </td>
            </tr>
          </tbody>
          <thead>
            <tr>
              <th scope="col">
                #
                <button type="button" class="btn btn-dark reset-sort-btn">
                  <i class="bi bi-arrow-clockwise reset-clockwise"></i>
                </button>
              </th>
              <th scope="col">
                Name
                <button
                  type="button"
                  onclick="namesSortHandler(1)"
                  class="btn btn-dark sort-names-btn"
                >
                  <i class="bi bi-arrow-up sort-names-arrow"></i>
                </button>
              </th>
              <th scope="col">Email</th>
              <th scope="col">
                Balance
                <button type="button" class="btn btn-dark sort-balance-btn">
                  <i class="bi bi-arrow-up sort-balance-arrow"></i>
                </button>
              </th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <th
                class="table-secondary"
                scope="row"
                style="color: black; font-weight: bold;"
              >
                4
              </th>
              <td class="table-secondary">
                <a
                  href="https://en.wikipedia.org/wiki/Dante_Alighieri"
                  target="_blank"
                  style="color: black; font-weight: bold;"
                >
                  Dante Alighieri
                </a>
              </td>
              <td
                class="table-secondary"
                style="color: black; font-weight: bold;"
              >
                [email protected]
              </td>
              <td
                class="table-secondary tdbalance"
                style="color: black; font-weight: bold;"
              >
                5000.21
              </td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td colspan="4" style="text-align: end; font-weight: bold;">
                Total balance: 13041.56
              </td>
            </tr>
          </tfoot>
        </table>
      </ul>
    </div>
  </div>
</div>;
javascript
  • 1 1 个回答
  • 28 Views

1 个回答

  • Voted
  1. Best Answer
    trincot
    2024-05-26T20:38:34+08:002024-05-26T20:38:34+08:00

    The problem occurs because the footer row has no third cell in its row. It has a merged cell spanning the whole row. And so the code that accesses cell[2].textContent raises an error because undefined has no textContent property. The slice call looks like an attempt to avoid this, but it comes to late: the error occurs before that slice executes.

    One way to resolve this is to only select the tr rows that are child of tbody. Then you shouldn't slice. Add the sorting and it will work:

    function sortTableByBalance() {
      const table = document.getElementById("myTable");
      // Only select rows that are not in THEAD or TFOOT:
      const tableRows = table.querySelectorAll("tr:not(thead>tr,tfoot>tr)");
      const arr = Array.from(tableRows, (row) => [row, +row.cells[3].textContent]);
      // No slice... but sort:
      arr.sort(([,a], [,b]) => a - b);
      for (const [elem] of arr) {
        table.appendChild(elem);
      }
    }
    

    Other Remarks

    With the above change it should work. But there are a few things that could be improved:

    • Your table creating function creates one tbody per row. Although this is allowed in HTML, this does not have any use in your case, and once you sort, all data rows will be moved out of their parent tbody anyhow. I would suggest adjusting your function, and just remove the tbody wrapping from your code and return the tr instead and append that directly to your table. Alternatively, you could work with exactly one tbody element. If you want the sorted rows to appear in that single tbody element, then make sure to update the above code in that final loop, so that it performs appendChild to that tbody element, not the table.

    • The code adds the thead in every iteration of the loop. Only the first time it would have a detectable effect. It would make more sense to place this before the loop, so it is only executed once, and also if the table happens to be empty.

    • Similarly, the addition to the table to the fragment should not be in the loop.

    • Instead of applying styles directly on your td elements, consider applying CSS classes. This is the better practice.

    • As you have quite some code repetition to create an element and then set its HTML attributes and text content, it would make sense to make a function for performing these actions on one given element: parameters would be that element, the attribute list and the text content. You could even have an optional argument for child element(s), so that you can create a whole hierarchy of elements in one expression. Or use a library like jQuery, that provides these features.

    • 1

相关问题

  • 合并排序不起作用 - Javascript代码:即使在调试后也无法找到错误

  • select.remove() 方法工作得很奇怪[关闭]

  • useOpenWeather() 中总是出现 401 res -react-open-weather lib [重复]

  • 输入元素没有只读属性,但字段仍然不可编辑[关闭]

  • 如何编辑 D3.js RadialTree 的第一个节点半径?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行?

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    何时应使用 std::inplace_vector 而不是 std::vector?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Marko Smith

    我正在尝试仅使用海龟随机和数学模块来制作吃豆人游戏

    • 1 个回答
  • Martin Hope
    Aleksandr Dubinsky 为什么 InetAddress 上的 switch 模式匹配会失败,并出现“未涵盖所有可能的输入值”? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge 为什么这个简单而小的 Java 代码在所有 Graal JVM 上的运行速度都快 30 倍,但在任何 Oracle JVM 上却不行? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini 具有指定基础类型但没有枚举器的“枚举类”的用途是什么? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer 何时应使用 std::inplace_vector 而不是 std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB 为什么 GCC 生成有条件执行 SIMD 实现的代码? 2024-02-17 06:17:14 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve