Проблема со смещением значений диапазона строк после поиска в таблице HTML

У меня есть таблица HTML, в которой используется атрибут rowspan. Я добавил в таблицу функцию поиска, но когда я ищу что-то вроде «Вашингтон», она удаляет значения «Обезьяна» и «Лев» из столбца ABC и заменяет их значениями из столбца DEF. Я не уверен, как это исправить. Есть ли у вас какие-либо рекомендации? Вот мой код -

function searchTable() {
  var input, filter, table, tr, td, i, j, txtValue, match;
  input  = document.getElementById("searchInput");
  filter = input.value.toUpperCase();
  table  = document.getElementById("example_full");
  tr     = table.getElementsByTagName("tr");
  match  = false;

  for (i = 1; i < tr.length; i++) {    // Skip the header row
    tr[i].style.display = "none";      // Hide all rows initially
    td                  = tr[i].getElementsByTagName("td");
    for (j = 0; j < td.length; j++) {
      if (td[j]) {
        txtValue = td[j].textContent || td[j].innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
          tr[i].style.display = "";
          match = true;
          break;
        }
      }
    }
  }

  // Show or hide the no match message
  document.getElementById("noMatch").style.display = match ? "none" : "block";
}
.no-match {
  display : none;
  color   : red;
}

th {
  border-left   : 1px solid #dddddd;
  border-top    : 1px solid #dddddd;
  border-bottom : 1px solid #dddddd;
  border-right  : 1px solid #dddddd;
  background-color: darkgray;
}
<input type = "text" id = "searchInput" placeholder = "Search for records..." onkeyup = "searchTable()" />
<p id = "noMatch" class = "no-match">No matching records found</p>

<table id = "example_full">
  <thead>
    <tr>
      <th>ABC</th>
      <th>DEF</th>
      <th>GHI</th>
      <th>XXX</th>
      <th>MMM</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan = "4" style = " vertical-align: middle;">MONKEY</td>
      <td>AD123</td>
      <td>434SDD</td>
      <td>DFDDFF</td>
      <td>FDFFD</td>
    </tr>
    <tr>
      <td>LEMON</td>
      <td>&#160;</td>
      <td>FDFGGF</td>
      <td>DFFDF</td>
    </tr>
    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FDDFF</td>
      <td>Edison</td>
    </tr>
    <tr>
      <td>FDDFFDF</td>
      <td>&#160;</td>
      <td>East</td>
      <td>Washington</td>
    </tr>
    <tr>
      <td rowspan = "3" style = " background-color: #F9F9F9; vertical-align: middle;">LION</td>
      <td>GFFG</td>
      <td>FGFGG</td>
      <td>FGFG</td>
      <td>FGGFGFG</td>
    </tr>
    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FGHGH</td>
      <td>DDDFF</td>
    </tr>
    <tr>
      <td></td>
      <td>test2</td>
      <td>FFGGFH</td>
      <td>Washington</td>
    </tr>
  </tbody>
</table>

Строка с надписью «ОБЕЗЬЯНА» скрывается. При поиске «Вашингтон» отображается только одна строка, и в этой строке всего 4 столбца. (Вероятно, сейчас самое время начать знакомиться с инструментами отладки вашего браузера. В частности, с проводником DOM, который показывает текущее состояние документа, а также с отладчиком сценариев, который позволяет вам пошагово просматривать код и наблюдать точные изменения. оно творится.)

David 03.07.2024 14:29

Вам нужно использовать диапазон строк? Что, если вы просто повторите значение «Обезьяна» для первых 4 строк и значение «Лев» для последних 3 строк. Если вы это сделаете, ваш код поиска и отображение будут работать правильно. @mplungjan прав, иначе становится довольно сложно управлять, когда <td> необходимо добавлять и удалять во время поиска.

M. Rizzo 03.07.2024 15:19

Мы только что дали вам отличный способ. Итак, теперь вы хотите показать весь набор строк, если текст найден в ячейках, являющихся частью диапазона строк? Таким образом, каждая строка, в которой есть ячейка с текстом фильтра, должна знать, что она является частью диапазона строк, и также показывать строку, содержащую этот диапазон строк?

mplungjan 03.07.2024 15:28
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
3
91
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Убедитесь, что в каждой строке по 5 ячеек. В вашем случае вы сворачиваете до 4 ячеек в строках, которые не имеют диапазона строк.

Вот более упрощенная версия, использующая предложение imhvost, чтобы свернуть видимость вместо отображения: нет/скрытый

const input = document.getElementById("searchInput");
const noMatch = document.getElementById("noMatch");
const rows = document.querySelectorAll("#example_full tbody tr");
const searchTable = () => {
  let filter = input.value.toUpperCase(),
  match = false;
  rows.forEach(row => {
    let found = filter && Array.from(row.querySelectorAll('td')).some(td => td.textContent.toUpperCase().includes(filter));
    row.style.visibility = filter && !found ? 'collapse' : 'visible';
    if (found) match = true; // set if any hit
  });  
  // Show or hide the no match message
   noMatch.hidden = !filter || (filter && match);
}
input.addEventListener('input',searchTable);
.no-match {
  color: red;
}

th {
  border-left: 1px solid #dddddd;
  border-top: 1px solid #dddddd;
  border-bottom: 1px solid #dddddd;
  border-right: 1px solid #dddddd;
  background-color: darkgray;
}
<input type = "text" id = "searchInput" placeholder = "Search for records..." />
<p id = "noMatch" hidden class = "no-match">No matching records found</p>

<table id = "example_full">
  <thead>
    <tr>
      <th>ABC</th>
      <th>DEF</th>
      <th>GHI</th>
      <th>XXX</th>
      <th>MMM</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan = "4" style = " vertical-align: middle;">MONKEY</td>
      <td>AD123</td>
      <td>434SDD</td>
      <td>DFDDFF</td>
      <td>FDFFD</td>
    </tr>

    <tr>
      <td>LEMON</td>
      <td>&#160;</td>
      <td>FDFGGF</td>
      <td>DFFDF</td>
    </tr>

    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FDDFF</td>
      <td>Edison</td>
    </tr>

    <tr>
      <td>FDDFFDF</td>
      <td>&#160;</td>
      <td>East</td>
      <td>Washington</td>
    </tr>



    <tr>
      <td rowspan = "3" style = " background-color: #F9F9F9; vertical-align: middle;">LION</td>
      <td>GFFG</td>
      <td>FGFGG</td>
      <td>FGFG</td>
      <td>FGGFGFG</td>
    </tr>



    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FGHGH</td>
      <td>DDDFF</td>
    </tr>

    <tr>
      <td></td>
      <td>test2</td>
      <td>FFGGFH</td>
      <td>Washington</td>
    </tr>

  </tbody>
</table>

Спасибо, но особой разницы не вижу. Если я поищу Вашингтон, столбцы все равно сместятся. Я что-то пропустил?

newuser 03.07.2024 14:42

Нет. Размах строк все портит.

mplungjan 03.07.2024 14:53

Используйте tr { visibility: collapse; } вместо tr { display: none; }:

document.getElementById('search-input').addEventListener('keyup', searchTable);

function searchTable() {
  const filter = this.value.toUpperCase();
  let isMatch = false;

  const tbody = document.querySelector('#example_full tbody');
  const noMatch = document.getElementById('no-match');

  if (!filter) {
    tbody.querySelectorAll('tr').forEach(tr => {
      tr.classList.remove('collapse', 'hidden');
    });
    noMatch.classList.remove('active');
    return;
  }

  let rowspanEndIndex = 0;

  tbody.querySelectorAll('tr').forEach((tr, index) => {
    tr.classList.add('collapse');
    tr.classList.remove('hidden');

    if (rowspanEndIndex === index) {
      rowspanEndIndex = 0;
    }
    tr.querySelectorAll('td').forEach(td => {
      td.removeAttribute('hidden');
      const rowspan = td.getAttribute('rowspan');
      if (rowspan) {
        rowspanEndIndex = index + Number(rowspan);
      }
      if (td.textContent && td.textContent.toUpperCase().includes(filter)) {
        tr.classList.remove('collapse');
        isMatch = true;
      }
    });
    if (rowspanEndIndex) {
      tr.setAttribute('data-group', rowspanEndIndex);
    }
  });
  document
    .querySelectorAll('#example_full tbody tr:has([rowspan])')
    .forEach(tr => {
      const group = tr.getAttribute('data-group');
      const trs = tbody.querySelectorAll(`tr[data-group = "${group}"]`).length;
      const collapseTrs = tbody.querySelectorAll(
        `tr[data-group = "${group}"].collapse`,
      ).length;
      if (trs !== collapseTrs) {
        tr.classList.remove('collapse');
        tr.querySelectorAll('td:not([rowspan])').forEach(td =>
          td.setAttribute('hidden', true),
        );
      }
    });
  noMatch.classList.toggle('active', !isMatch);
}
.no-match {
  color: red;
  &:not(.active) {
    display: none;
  }
}

table {
  border-collapse: collapse;
}

td,
th {
  padding: 2px 8px;
}

th {
  border: 1px solid #dddddd;
  background-color: darkgray;
}

tr.collapse {
  visibility: collapse;
}
<input
  type = "text"
  id = "search-input"
  placeholder = "Search for records..."
/>
<p
  id = "no-match"
  class = "no-match"
>
  No matching records found
</p>

<table id = "example_full">
  <thead>
    <tr>
      <th>ABC</th>
      <th>DEF</th>
      <th>GHI</th>
      <th>XXX</th>
      <th>MMM</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td
        rowspan = "4"
        style = "vertical-align: middle"
      >
        MONKEY
      </td>
      <td>AD123</td>
      <td>434SDD</td>
      <td>DFDDFF</td>
      <td>FDFFD</td>
    </tr>
    <tr>
      <td>LEMON</td>
      <td>&#160;</td>
      <td>FDFGGF</td>
      <td>DFFDF</td>
    </tr>
    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FDDFF</td>
      <td>Edison</td>
    </tr>
    <tr>
      <td>FDDFFDF</td>
      <td>&#160;</td>
      <td>East</td>
      <td>LEMON</td>
    </tr>
    <tr>
      <td>One tr</td>
      <td>&#160;</td>
      <td>LEMON</td>
      <td>DDDFF</td>
    </tr>
    <tr>
      <td
        rowspan = "3"
        style = "background-color: #f9f9f9; vertical-align: middle"
      >
        LION
      </td>
      <td>GFFG</td>
      <td>FGFGG</td>
      <td>FGFG</td>
      <td>FGGFGFG</td>
    </tr>
    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FGHGH</td>
      <td>DDDFF</td>
    </tr>
    <tr>
      <td></td>
      <td>test2</td>
      <td>FFGGFH</td>
      <td>Washington</td>
    </tr>
  </tbody>
</table>

Отличный. Отличная работа. Будь ты проклят! ;)

mplungjan 03.07.2024 15:13

Отлично, большое спасибо. Это работает хорошо. Есть ли способ показать значение столбца ABC, если я ищу «Лимон». В столбце ABC должна отображаться Обезьяна. Спасибо.

newuser 03.07.2024 15:25
Ответ принят как подходящий

Согласно вашему комментарию: «Есть ли способ показать значение столбца ABC, если я ищу «Лимон», вот решение, которое будет создавать и удалять ячейки и метки по мере необходимости. Я попытался добавить некоторые базовые комментарии к js-коду, чтобы объяснить, что происходит.

function searchTable() {
  var input, filter, table, tr, th, td, i, j, txtValue, match, rowSpan, rowSpanData;
   input  = document.getElementById("searchInput");
   filter = input.value.toUpperCase();
   table  = document.getElementById("example_full");
   tr     = table.getElementsByTagName("tr");
   th     = table.getElementsByTagName("th");
   match  = false;

  rowSpan = 1;
  rowSpanData = '';

  for (i = 1; i < tr.length; i++) {    // Skip the header row
    tr[i].style.display = "none";      // Hide all rows initially
    td                  = tr[i].getElementsByTagName("td");
    //console.info("TD Length = " + td.length);
    
    //Loop through the cells
    for (j = 0; j < td.length; j++) {

    if (td[j]) {
    
    if (filter! = "") {
        if (j==0 && td.length == th.length){
          rowSpanData = td[j].innerHTML;
        }
        
        //If there is a match 
        txtValue = td[j].textContent || td[j].innerText;
        if (txtValue.toUpperCase().indexOf(filter) > -1) {
           
             tr[i].style.display = "";
             //match boolean to be used for display of match message at end of fucntion
             match = true;
           

          if (td.length == th.length && td[0].hasAttribute("rowspan") && td[0].getAttribute("rowspan") != 1) {
            td[0].setAttribute("originalRowSpan", td[0].getAttribute("rowspan"));
            td[0].setAttribute("rowspan", 1);
          }
          if (td.length < th.length){
             var newCell = tr[i].insertCell(0);
             newCell.classList.add("removeMe");
             newCell.innerHTML= rowSpanData;
          }
          // skip to the next row
          continue;
        } //end of match section

        } else {
          tr[i].style.display = "";
            if (td[j].hasAttribute("rowspan")){
              td[j].setAttribute("rowspan", td[j].getAttribute("originalRowSpan"));
            } else if (td[j].classList.contains("removeMe")){
              tr[i].deleteCell(0);
            }
        }
          
      } 
    } // end of cell loop
  } // end of row loop

  // Show or hide the no match message
  document.getElementById("noMatch").style.display = match ? "none" : "block";
}
.no-match {
  display : none;
  color   : red;
}

th {
  border-left   : 1px solid #dddddd;
  border-top    : 1px solid #dddddd;
  border-bottom : 1px solid #dddddd;
  border-right  : 1px solid #dddddd;
  background-color: darkgray;
}
<input type = "text" id = "searchInput" placeholder = "Search for records..." onkeyup = "searchTable()" />
<p id = "noMatch" class = "no-match">No matching records found</p>

<table id = "example_full">
  <thead>
    <tr>
      <th>ABC</th>
      <th>DEF</th>
      <th>GHI</th>
      <th>XXX</th>
      <th>MMM</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td rowspan = "4" style = " vertical-align: middle;">MONKEY</td>
      <td>AD123</td>
      <td>434SDD</td>
      <td>DFDDFF</td>
      <td>FDFFD</td>
    </tr>
    <tr>
      <td>LEMON</td>
      <td>&#160;</td>
      <td>FDFGGF</td>
      <td>DFFDF</td>
    </tr>
    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FDDFF</td>
      <td>Edison</td>
    </tr>
    <tr>
      <td>FDDFFDF</td>
      <td>&#160;</td>
      <td>East</td>
      <td>Washington</td>
    </tr>
    <tr>
      <td rowspan = "3" style = " background-color: #F9F9F9; vertical-align: middle;">LION</td>
      <td>GFFG</td>
      <td>FGFGG</td>
      <td>FGFG</td>
      <td>FGGFGFG</td>
    </tr>
    <tr>
      <td>&#160;</td>
      <td>&#160;</td>
      <td>FGHGH</td>
      <td>DDDFF</td>
    </tr>
    <tr>
      <td></td>
      <td>test2</td>
      <td>FFGGFH</td>
      <td>Washington</td>
    </tr>
  </tbody>
</table>

Отлично работает, большое спасибо

newuser 03.07.2024 16:44

Хорошо, когда ЛИМОН один))

imhvost 03.07.2024 17:06

Сделать это не так-то просто, но:

  • Элемент таблицы <TR> имеет свойство hidden, позволяющее показать/скрыть всю строку.
  • Я также использую свойства .rows и .cells.

const 
  inSearch  = document.querySelector('#search-input')
, msg_match = document.querySelector('#match-msg')
, expl_TB   = document.querySelector('#example_full tbody')
  ;
function searchTable()
  {
  const 
    inFind = inSearch.value.trim()
  , inRgx  = new RegExp( inFind, 'gi')
    ;
  expl_TB.querySelectorAll('td.matched').forEach( td => td.classList.remove('matched'));
  expl_TB.querySelectorAll('tr')        .forEach( tr => tr.hidden = false );

  if ( inFind === '' )  // input is empty....
    {
    inSearch.value = '';
    msg_match.classList.remove('noVisible'); 
    return;
    }

  // find process...
  let
    matchingCount = 0
  , rowParentIdxZ = 0
  , rowParentLast = 0
  , rowShowed     = new Set()
    ;

  for (let tr of expl_TB.rows )
    {
    let parent = getParentIdxZ( tr );

    for (let td of tr.cells)   // Find matching cells...
      {
      if (inRgx.test(td.textContent ))
        {
        matchingCount++;
        td.classList.add('matched');
        rowShowed.add(parent);
        }
      }
    }

  if ( matchingCount === 0)  // no cells matching
    {
    msg_match.classList.remove('noVisible'); 
    return;
    }

  msg_match.classList.add('noVisible'); 

  for (let tr of expl_TB.rows ) // hide unmatched rows...
    {
    tr.hidden = !rowShowed.has( getParentIdxZ( tr ) );
    }

  function getParentIdxZ( tr )  // sub function...
    {
    let idxZ = tr.rowIndex -1;  // use indexing where first index value is Zero;

    if (tr.cells[0].rowSpan > 1 )
      {
      rowParentIdxZ = idxZ
      rowParentLast = idxZ + tr.cells[0].rowSpan; 
      }
    return (idxZ < rowParentLast) ? rowParentIdxZ : idxZ;
    }
  }
body {
  font-family     : Arial, Helvetica, sans-serif;
  font-size       : 14px;
  }
table {
  background      : darkblue;
  border-collapse : separate;
  border-spacing  : 1px;
  }
th {
  background-color : #7fccff;
  padding          : .4em .6em ;
  }
td {
  background-color : whitesmoke;
  padding          : .6em .4em;
  }
.matched {
  color      : red;
  background : lightgreen;
  }
#match-msg {
  margin-top    : 0.3em;
  margin-bottom : 1em;
  padding-left  : 2em;
  color         : darkblue;
  }
.noVisible {
  visibility : hidden;
  }
<input  id = "search-input" type = "text" placeholder = "Search for records..." onkeyup = "searchTable()" />
<p id = "match-msg" >No matching records found</p>

<table id = "example_full">
  <thead>
    <tr> <th>ABC</th><th>DEF</th><th>GHI</th><th>XXX</th><th>MMM</th> </tr>
  </thead>
  <tbody>
    <tr><td rowspan = "4">MONKEY</td><td>AD123</td><td>434SDD</td><td>DFDDFF</td><td>FDFFD</td> </tr>
    <tr><td>LEMON</td><td>&#160;</td><td>FDFGGF</td><td>DFFDF</td> </tr>
    <tr><td>&#160;</td><td>&#160;</td><td>FDDFF</td><td>Edison</td> </tr>
    <tr><td>FDDFFDF</td><td>&#160;</td><td>East</td><td>Washington</td> </tr>

    <tr><td>a</td><td>Mister</td><td>Jojo</td><td>d</td><td>e</td> </tr>

    <tr><td rowspan = "3">LION</td><td>GFFG</td><td>FGFGG</td><td>FGFG</td><td>FGGFGFG</td> </tr>
    <tr><td>&#160;</td><td>&#160;</td><td>FGHGH</td><td>DDDFF</td> </tr>
    <tr><td></td><td>test2</td><td>FFGGFH</td><td>Washington</td> </tr>
  </tbody>
</table>

Другие вопросы по теме