Bootstrap 4: фильтровать карточки на основе заголовка (.card-title) и тега (.badge)

#javascript #jquery #html #bootstrap-4

#javascript #jquery #HTML #bootstrap-4

Вопрос:

Я пытаюсь создать карточки с возможностью поиска, используя html, javascript и bootstrap 4, но я не могу заставить свой код работать. Я хочу отфильтровать эти три карточки с помощью панели поиска на основе их заголовка ( h5.card-title ) и тегов ( a.badge ).

Вот HTML:

 <!DOCTYPE html>
<html lang="en">

<head>
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X 965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH 8abtTE1Pi6jizo" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM B07jRM" crossorigin="anonymous"></script>

  <script src="filter.js"></script>
</head>
<body>
  <input type="text" id="myFilter" class="form-control" onkeyup="myFunction()" placeholder="Search for names..">
  <div class="container">
    <div id="myItems">
      <div class="row">
        <div class="p-3">
          <div class="card" style="width: 18rem;">
            <img class="card-img-top" src="..." alt="Card image cap">
            <div class="card-body">
              <h5 class="card-title">Title One</h5>

              <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
                <button type="button" class="btn btn-primary">Button</button>

                <div class="btn-group" role="group">
                  <button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    </button>
                  <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
                    <a class="dropdown-item" href="#">Option 1</a>
                    <a class="dropdown-item" href="#">Option 2</a>
                  </div>
                </div>
              </div>
            </div>
            <div class="card-footer">
              <a href="#" class="badge badge-secondary">first tag</a>
              <a href="#" class="badge badge-secondary">second tag</a>
            </div>
          </div>
        </div>
        <div class="p-3">
          <div class="card" style="width: 18rem;">
            <img class="card-img-top" src="..." alt="Card image cap">
            <div class="card-body">
              <h5 class="card-title">Title Two</h5>
              <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
                <button type="button" class="btn btn-primary">Button</button>
                <div class="btn-group" role="group">
                  <button id="btnGroupDrop2" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></button>
                  <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
                    <a class="dropdown-item" href="#">Option 1</a>
                    <a class="dropdown-item" href="#">Option 2</a>
                  </div>
                </div>
              </div>
            </div>
            <div class="card-footer">
              <a href="#" class="badge badge-secondary">different tag</a>
              <a href="#" class="badge badge-secondary">unique tag</a>
            </div>
          </div>
        </div>
        <div class="p-3">
          <div class="card" style="width: 18rem;">
            <img class="card-img-top" src="..." alt="Card image cap">
            <div class="card-body">
              <h5 class="card-title">Title Three</h5>
              <div class="btn-group" role="group" aria-label="Button group with nested dropdown">
                <button type="button" class="btn btn-primary">Button</button>
                <div class="btn-group" role="group">
                  <button id="btnGroupDrop3" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    </button>
                  <div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
                    <a class="dropdown-item" href="#">Option 1</a>
                    <a class="dropdown-item" href="#">Option 2</a>
                  </div>
                </div>
              </div>
            </div>
            <div class="card-footer">
              <a href="#" class="badge badge-secondary">another tag</a>
              <a href="#" class="badge badge-secondary">last tag</a>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>
</html>  

Вот Javascript:

 function myFunction() {
  var input, filter, cards, cardContainer, h5, title, i;
  input = document.getElementById("myFilter");
  filter = input.value.toUpperCase();
  cardContainer = document.getElementById("myItems");
  cards = cardContainer.getElementsByClassName("card");
  for (i = 0; i < cards.length; i  ) {
    title = cards[i].querySelector(".card-body h5.card-title, .card-footer a.badge");
    if (title.innerText.toUpperCase().indexOf(filter) > -1) {
      cards[i].style.display = "";
    } else {
      cards[i].style.display = "none";
    }
  }
}  

Он фильтрует только на основе тегов или заголовка, он не будет выполнять оба.
Пожалуйста, помогите.

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

1. Проверьте querySelector , последняя часть должна быть .card-footer a.badge . Это даст вам массив элементов (а не один), который затем вам нужно будет проверять в цикле на наличие внутреннего текста один за другим.

2. Я исправил это, все еще не работает

Ответ №1:

Вот мое решение. Используется querySelectorAll отдельно .card-title и a.badge отдельно, вместо querySelector и повторяется card_titles и выполняется keep_card = true , если мы нашли текст поиска. Затем, если функция все еще ничего не нашла, она выполняет поиск badge_titles таким же образом.

И последнее, но не менее важное: если keep_card = true он показывает карточку, иначе он ее скрывает.

 function myFunction() {
    var input, filter, cards, cardContainer, h5, keep_card, card_titles, badge_texts, i, j;

    input = document.getElementById("myFilter");
    filter = input.value.toUpperCase();
    cardContainer = document.getElementById("myItems");
    cards = cardContainer.getElementsByClassName("card");
    for (i = 0; i < cards.length; i  ) {
        //We will switch keep_card to true if we find search text in badge or title
        keep_card = false;
        //querySelectorAll returns all elements of a.badge. querySelector returns only the first element
        card_titles = cards[i].querySelectorAll(".card-body h5.card-title");
        badge_texts = cards[i].querySelectorAll(".card-footer a.badge");

        //You must loop through all card titles.
        for(j = 0; j < card_titles.length; j  ) {
            if (card_titles[j].innerText.toUpperCase().indexOf(filter) > -1) {
                //Found search text, now lets switch keep_card on
                keep_card = true;
                //No need for further looping, we found the card, there we break loop
                break;
            }
        }

        if(!keep_card) {
            for(j = 0; j < badge_texts.length; j  ) {
                if (badge_texts[j].innerText.toUpperCase().indexOf(filter) > -1) {
                    keep_card = true;
                    break;
                }
            }
        }

        if(keep_card) {
            cards[i].style.display = "";
        } else {
            cards[i].style.display = "none";
        }

    }
}
  

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

1. Круто, спасибо! 🙂