Simple Shuffle.js search not working with Bootstrap 4 cards

北战南征 提交于 2021-01-29 02:05:36

问题


So, I've been trying for the last days to get Shuffle.js to work with my cards in Bootstrap 4, in order to have a nice shuffling effect when searching/filtering those cards.

Here follows the structure of my HTML and my JS. You can also find here the JSFiddle.net link.

class Card {
  constructor(ref) {
    this.hmi_ref = ref;

    // Bootstap : container type
    this.BS = {}
    this.BS.container = document.createElement('div');
    this.BS.card = document.createElement('div');
    this.BS.image = document.createElement('img');
    this.BS.info = document.createElement('div');
    this.BS.title = document.createElement('h4');
    this.BS.link = document.createElement('a');

    this.BS.card.appendChild(this.BS.link);
    this.BS.link.appendChild(this.BS.image);
    this.BS.card.appendChild(this.BS.title);
    this.BS.container.appendChild(this.BS.card);

    this.BS.container.className = 'col-4 mb-3';
    this.BS.card.className = 'card h-100';
    this.BS.image.className = 'card-img-top';
    this.BS.title.className = 'card-title text-center align-middle';
  }

  add(name, image, page_link) {
    this.BS.image.src = image;
    this.BS.title.textContent = name;
    this.BS.link.href = page_link;
    let newNode = this.BS.container.cloneNode(true);
    this.hmi_ref.appendChild(newNode);
  }
}

let myCard = new Card( document.getElementById('card-space') );
[
    {title: 'Vacanza studio Londra', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Roma', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Bangkok', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Catania', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanze studio"},
    {title: 'Vacanza studio Siracusa', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Ragusa', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Trapani', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
].map(e => myCard.add(e.title, e.img, e.link, e.category));

class Shuffler {
    constructor(element) {
        this.shuffle = new window.Shuffle(element, {
            itemSelector: '.card',
            sizer: element.querySelector('.sizer'),
        }); 
        document.getElementById('searchBox').addEventListener('keyup', this._handleSearchKeyup.bind(this));
    }

    /**
     * Filter the shuffle instance by items with a title that matches the search input.
     * @param {Event} evt Event object.
     */
    _handleSearchKeyup(evt) {
        const searchText = evt.target.value.toLowerCase();
        this.shuffle.filter(element => {
            console.log('filtering...');
            const titleText = element.querySelector('.card-title').textContent.toLowerCase().trim();
            return titleText.indexOf(searchText) !== -1;
        });
    }
}

window.onload = () => {
    window.demo = new Shuffler(document.querySelector('#card-space'));
}  
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">

<div class="container pt-3">
  <div class="row">
    <div class="col">
      <!-- Main column -->
      <div class="row pt-4">
        <div class="col-9">
          <div id="card-space" class="row h-100">
            <div class="col-1@sm sizer"></div>
          </div>
        </div>
        <div class="col-3">
          <div class="row">
            <form class="form-inline" action="javascript:void(0);">
              <div class="input-group">
                <div class="input-group-prepend">
                  <div class="input-group-text"><i class="fa fa-search" aria-hidden="true"></i></div>
                </div>
                <input id="searchBox" class="form-control" type="search" placeholder="Cerca" aria-label="Cerca">
              </div>
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<script src="https://unpkg.com/shufflejs@5"></script>
<!-- jQuery first, then Popper.js and then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>

In addition, the point in which I think it definitely breaks is the following

this.shuffle.filter(element => {
    const titleText = element.querySelector('.card-title').textContent.toLowerCase().trim();
    return titleText.indexOf(searchText) !== -1;
});

as I cannot be able to debug inside it.

Does anyone have any ideas about the solution to this problem? I've been finding the Shuffle.js library pretty as complicate as smooth is the feeling I get when seeing the final (desired!) effect.


回答1:


Take a look at this demo. What I've done is remove the entire grid structure completely and went for Bootstrap's card-deck. The reason for this, because of the way this library looks for the items array to filter on.

_getItems() {
    return Array.from(this.element.children)
        .filter(el => matches(el, this.options.itemSelector))
        .map(el => new ShuffleItem(el));
}

This basically means it takes the direct children and matches your itemSelector. In your HTML structure it takes all the columns, and can't find any itemSelector classes on your columns.

Another important step was to use the data-groups and/or data-title. Now I've set it only for the title (name) but I believe your goal is to add separate groups as well. You can fill those in from the category selector you've already created (with only one option tho).

this.BS.card.setAttribute('data-title', name);
this.BS.card.setAttribute('data-groups', name);

This solution enables the filter, enables the height and only left is now making .card-deck responsive, as card-deck is great (I'm on repeat here).

Arrange multiple divs in CSS/JS?
loop every 3 row using bootstrap card
How do I add spacing between rows of a card-deck in bootstrap

responsive card-deck CSS demo




回答2:


You can filter Array not an Object. I do console.log so you can see it.

class Card {
  constructor(ref) {
    this.hmi_ref = ref;

    // Bootstap : container type
    this.BS = {}
    this.BS.container = document.createElement('div');
    this.BS.card      = document.createElement('div');
    this.BS.image     = document.createElement('img');
    this.BS.info      = document.createElement('div');
    this.BS.title     = document.createElement('h4');
    this.BS.link      = document.createElement('a');

    this.BS.card.appendChild(this.BS.link);
    this.BS.link.appendChild(this.BS.image);
    this.BS.card.appendChild(this.BS.title);
    this.BS.container.appendChild(this.BS.card);

    this.BS.container.className = 'col-4 mb-3';
    this.BS.card.className      = 'card h-100';
    this.BS.image.className     = 'card-img-top';
    this.BS.title.className     = 'card-title text-center align-middle';
  }

  add ( name, image, page_link){
    this.BS.image.src = image;
    this.BS.title.textContent = name;
    this.BS.link.href = page_link;
    let newNode = this.BS.container.cloneNode(true);
    this.hmi_ref.appendChild(newNode);
  }
}
      
let myCard = new Card( document.getElementById('card-space') );
[
    {title: 'Vacanza studio Londra', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Roma', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Bangkok', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Catania', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanze studio"},
    {title: 'Vacanza studio Siracusa', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Ragusa', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
    {title: 'Vacanza studio Trapani', img: 'https://source.unsplash.com/random/1920x1080', link: 'https://source.unsplash.com/random/1920x1080', category: "Vacanza studio"},
].map(e => myCard.add(e.title, e.img, e.link, e.category));

class Shuffler {
    constructor(element) {
        this.shuffle = new window.Shuffle(element, {
            itemSelector: '.card',
            sizer: element.querySelector('.sizer'),
        }); 
        document.getElementById('searchBox').addEventListener('keyup', this._handleSearchKeyup.bind(this));
    }

    /**
     * Filter the shuffle instance by items with a title that matches the search input.
     * @param {Event} evt Event object.
     */
    _handleSearchKeyup(evt) {
        const searchText = evt.target.value.toLowerCase();
        Object.values(this.shuffle.element.children).filter(element => {
            const titleText = element.textContent.toLowerCase().trim();
            console.log(element.textContent.toLowerCase().trim(), titleText.indexOf(searchText));
            return titleText.indexOf(searchText) !== -1;
        });
    }
}

window.onload = () => {
    window.demo = new Shuffler(document.querySelector('#card-space'));
}   
</script>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
</head>

<body>
  <div class="container pt-3">
    <div class="row">
      <div class="col">
        <!-- Main column -->
        <div class="row pt-4">
          <div class="col-9">
            <div id="card-space" class="row">
              <!-- <div class="col-1@sm sizer"></div> -->
            </div>
          </div>
          <div class="col-3">
            <div class="row">
              <form class="form-inline" action="javascript:void(0);">
                <div class="input-group">
                  <div class="input-group-prepend">
                    <div class="input-group-text"><i class="fa fa-search" aria-hidden="true"></i></div>
                  </div>
                  <input id="searchBox" class="form-control" type="search" placeholder="Cerca" aria-label="Cerca">
                </div>
              </form>
            </div>
            <div class="row">
              <select class="custom-select my-3" id="eventCategories">
                <option selected>Scegli una categoria</option>
              </select>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/Shuffle/5.2.3/shuffle.min.js"></script>
  <!-- jQuery first, then Popper.js and then Bootstrap JS -->
  <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
</body>

</html>


来源:https://stackoverflow.com/questions/61296253/simple-shuffle-js-search-not-working-with-bootstrap-4-cards

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!