iT邦幫忙

2021 iThome 鐵人賽

DAY 4
0
  • Multiple criteria filter

繼眾裡尋它後,我們想繼續看是否有各個欄位都符合關鍵字的結果(真命天菜/女神?),這需要根據輸入的資料的陣列大小自動調整輸入的欄位和對應function的數目,而這功能我問Google大神並沒有得到明確的答案,但想想是可以實現的,分成3個部分,分別為生成輸入欄位、比對有輸入值得欄位做filter,以及調整輸入欄位的寬度(如果資料表格會根據內容調整寬度)。

  • Implement

首先我們要修正上次的filterTable這個function,將原本input和table這兩個argument改為,並在function內用getElementById取得HTML上的內容,這樣就不用外面再包一層(原本filterTable_data()是拗口的寫法),第二是再增加一個hold的argument,再原本if (txtValue.indexOf(filter) > -1)的條件中,再增加if (!hold)的條件,當兩個條件都達到時,才會有display = "",這是避免在多個條件時,在其中一個條件達成時,會洗掉其他條件的沒達成(display = "none"):

function filterTable(inputId, tableId, index, hold) {
  let input = document.getElementById(inputId);
  let table = document.getElementById(tableId);
  // Declare variables
  let filter, tr, td, i, txtValue;
  filter = input.value;
  tr = table.getElementsByTagName("tr");
  // Loop through all table rows, and hide those who don't match the search query
  for (i = 1; i < tr.length; i++) {
    td = tr[i].getElementsByTagName("td")[index];
    if (td) {
      txtValue = td.textContent || td.innerText;
      if (txtValue.indexOf(filter) > -1) {
        if (!hold) {
          tr[i].style.display = "";
        }
      } else {
        tr[i].style.display = "none";
      }
    }
  }
}

接下來是生成輸入欄位,我們可以使用在day2生成表格的做法,而同樣我們會生成表格,並根據原本表格的欄位的寬度寫入屬性,這樣輸入欄位就會對齊(如果原本表格是自動根據內容調整寬度),然後在cell中寫入輸入,如同在單一輸入時的寫法,但要額外帶著欄位標號以做區分。總結,用JavaScript寫表格,用表頭格式(與下放表格的表頭外觀會一致),每個cell()根據資料的表格讀取寬度並填入,cell寫入輸入(我在一開始將固定的文字拆成string1~string5,對應到上方的註解,讓後面loop中的code比較乾淨):

function genTableFilter(outputId, tableId, keyName) {
  //<input type="text" id="filterInput_data" onkeyup="filterTable_multi('filterInput_data', 'searchTable_data', 'dataTable', 0)" placeholder="Search ..." class="form-control"/>
  const string1 = "<input type=\"text\" id=\"filterInput_";
  const string2 = "\" onkeyup=\"filterTable_multi(\'filterInput_";
  const string3 = "\', \'";
  const string4 = "\', ";
  const string5 = ")\" placeholder=\"Search ...\" class=\"form-control\"/>";
  let table = document.getElementById(tableId);
  td = table.getElementsByTagName("tr")[0].getElementsByTagName("th");

  let content = "<thead><tr>";
  for (let i = 0; i < td.length; i++) {
    //content += "<th>" + cell + "</th>" ;
    let cellWidth = table.rows[0].cells[i].offsetWidth;
    content += "<th width=" + cellWidth + ">" + string1 + keyName + i;
    content += string2 + keyName + i + string3 + outputId + string3 + tableId + string4 + i;
    content += string5 + "</th>";
  }
  content += "</tr></thead>";
  document.getElementById(outputId).innerHTML = content;
}

再來是比對有輸入值的欄位做filter,我們邏輯是這樣:如果輸入欄位有修改值(onkeyup觸發),則會依序對所有欄位都讀取值,如果有值(!= "")則做filter(filterTable這個function),而只有第一個hold為false,也就是會將符合條件的display設為"",這樣可以清除之前的設定,而之後的所做filter的hold為true,則不會洗掉前面判斷display = "none"的結果。若loop後hold還是false,表示所有欄位都沒有輸入值,則同樣做一次filter,將所有display = "none"清回display = "",而最後呼叫的adjuctTableWidthByTable則是下一段所要說明調整寬度的function:

function filterTable_multi(inputId, searchId, tableId, index) {
  let table = document.getElementById(tableId);
  td = table.getElementsByTagName("tr")[0].getElementsByTagName("th");
  let hold = false;
  for (let i = 0; i < td.length; i++) {
    let inputId_other = inputId.replace(/(\d+)$/, i);
    if (document.getElementById(inputId_other).value != "") {
      filterTable(inputId_other, tableId, i, hold);
      hold = true;
    }
  }
  if (!hold) {filterTable(inputId, tableId, index, hold);}
  adjuctTableWidthByTable(tableId, searchId);
}

如果資料表格會根據內容調整寬度,則我們在做filter時由於資料變了,則表格的寬度也可能變動,這樣輸入欄位可能會不對齊,這在使用時會有不協調的感覺。我們同樣可以用之前在生成欄位的方式,再用loop依序抓一次資料表格的寬度,然後調整輸入欄位寬度的屬性:

function adjuctTableWidthByTable(refTableId, targetTableId) {
  let refTable = document.getElementById(refTableId);
  let tarTable = document.getElementById(targetTableId);
  td = refTable.getElementsByTagName("tr")[0].getElementsByTagName("th");
  for (let i = 0; i < td.length; i++) {
    let cellWidth = refTable.rows[0].cells[i].offsetWidth;
    //console.log(cellWidth);
    tarTable.getElementsByTagName("tr")[0].getElementsByTagName("th")[i].width = cellWidth;
    //console.log(tarTable.rows[0].cells[i].offsetWidth);
  }
}

最後我以節錄一開始的Bootstrap所附的表格資料做測試,因為資料的內容長度不一致,可以看出第三個調整寬度的功能的結果。
兩欄filter輸入結果:
https://ithelp.ithome.com.tw/upload/images/20210905/20141158H4CAOXqI5I.jpg
無符合條件結果:
https://ithelp.ithome.com.tw/upload/images/20210905/20141158FkgBzKciYs.jpg
無輸入條件結果:
https://ithelp.ithome.com.tw/upload/images/20210905/20141158YxoBMwgjVt.jpg


上一篇
Day3 眾裡尋它千百度
下一篇
Day5 請多關懷邊緣人
系列文
以網頁呈現資料視覺化30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言