Search Results

Flexbox container of card components.

Once the user scrolls to the bottom of the page:

  1. the data-next attribute is checked to see if it contains a URL of more results
  2. if the data-next value is present, an additional request is made
  3. the loading card is shown
  4. once the request JSON is returned
  5. update the data-next value
  6. insert the new card search results
  7. hide the loading card

This repeats until the data-next attribute is not present.

The scroll event won't be triggered in the documentation.

Search Results

loading

<!-- start `search-results` component;-->
<div class="search-results" data-next="../json/search-results/search-results-2.json">
  <div class="search-results__title">
    <h1>120 Results were found for &ldquo;foo-bar-baz&rdquo;</h1>
  </div>
  <div class="search-results__stories">
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Curabitur in ligula viverra sagittis nunc et</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Ut ut nunc a odio blandit ultrices ac sed purus</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Vestibulum ut lectus sit amet tortor mollis</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Quisque vitae lacus non purus efficitur</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Mauris ut diam eu diam commodo ornare et</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Fusce ac leo eget lorem eleifend fringilla</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Maecenas volutpat augue sed elementum</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Sed quis diam a tortor tempor hendrerit</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Aliquam consectetur ipsum eget turpis</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Volutpat augue sed ele mentum maecenas</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Diam a tortor tempor hend rerit sed quis</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Ipsum eget turpis aliquam conse ctetur</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Cras sollicitudin sapien et odio venenatis</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Nulla interdum turpis sit amet feugiat faucibus</h2>
      </a> </article>
    <!-- end `card` component; -->
    <!-- start `card` component; -->
    <article class="card card--overlay"><a href="#">
        <div class="img-cover"><img src="http://via.placeholder.com/320x320" alt="empty placeholder image" /></div>
        <h2>Pellentesque laoreet urna non interdum egestas</h2>
      </a> </article>
    <!-- end `card` component; -->
    <div class="search-results__card-loading">
      <div class="icon-container">
        <svg class="icon-spin-alt">
          <use xlink:href="../images/icons/icons.svg#icon-spin-alt"></use>
        </svg>
      </div>
    </div>
  </div>
  <script id="search-results__card-template" type="text/x-custom-template">
    <!-- start `card` component; -->
    <article class="card card--overlay"><a>
        <div class="img-cover"><img/></div>
        <h3></h3></a> </article>
    <!-- end `card` component; -->
  </script>
</div>
<!-- end `search-results` component; -->
{
  "next": "../json/search-results/search-results-2.json",
  "stories": [
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Curabitur in ligula viverra sagittis nunc et",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Ut ut nunc a odio blandit ultrices ac sed purus",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Vestibulum ut lectus sit amet tortor mollis",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Quisque vitae lacus non purus efficitur",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Mauris ut diam eu diam commodo ornare et",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Fusce ac leo eget lorem eleifend fringilla",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Maecenas volutpat augue sed elementum",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Sed quis diam a tortor tempor hendrerit",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Aliquam consectetur ipsum eget turpis",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Volutpat augue sed ele mentum maecenas",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Diam a tortor tempor hend rerit sed quis",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Ipsum eget turpis aliquam conse ctetur",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Cras sollicitudin sapien et odio venenatis",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Nulla interdum turpis sit amet feugiat faucibus",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    },
    {
      "img": "http://via.placeholder.com/320x320",
      "alt": "empty placeholder image",
      "title": "Pellentesque laoreet urna non interdum egestas",
      "url": "#",
      "addClass": "card--overlay",
      "h2": true
    }
  ]
}
import { debounce as _debounce } from 'lodash';

jQuery(($: JQueryStatic) => {
  const $searchResults = $('.search-results');
  const $stories = $('.search-results__stories');
  const $loadingCard = $('.search-results__card-loading');
  const cardTemplate = $('#search-results__card-template').html();
  let loading = false;

  $(window).on('scroll', _debounce(calculatePosition, 150));

  // run onload in case the user is already at the bottom of the page;
  calculatePosition();

  function calculatePosition() {
    const position = window.scrollY + window.innerHeight;
    const height = document.body.scrollHeight;
    const distanceFromBottom = height - position;

    if (distanceFromBottom < 120) {
      const url = $searchResults.data('next');

      if (loading === false && url) {
        getMoreResults(url);
        showLoading();
      }
    }
  }

  function showLoading() {
    loading = true;
    $loadingCard.fadeIn();
  }

  function hideLoading() {
    loading = false;
    $loadingCard.fadeOut();
  }

  function getMoreResults(url: string) {
    $.get(url, processResults);
  }

  function processResults(response: any) {
    // add delay so the user can see something happening;
    window.setTimeout(() => {
      // add each story to the DOM;
      response.stories.forEach(story => {
        const $card = $(cardTemplate);

        $card
          .find('a')
          .attr('href', story.url)
          .find('img')
          .attr('src', story.img)
          .attr('alt', story.alt)
          .end()
          .end()
          .find('h3')
          .text(story.title);

        $card.insertBefore($loadingCard);
      });

      // change the next Ajax request URL (if present);
      $searchResults.data('next', response.next || null);

      // remove the loading indicator;
      hideLoading();
    }, 2500);
  }
});
.search-results {
  &__title {
    padding: size(2) 0 0;

    h1 {
      font-size: $font-size__large;
    }
  }

  &__stories {
    display: flex;
    flex-wrap: wrap;
    padding-top: size(0.5);
    margin: 0 size(0.5) * -1;
  }

  .card,
  &__card-loading {
    width: calc(50% - #{size(1)});
    margin: size(0.5);

    @include breakpoint($breakpoint--md) {
      width: calc(25% - #{size(1)});
    }
  }

  &__card-loading {
    display: none;

    .icon-container {
      background: $color__backgroundDark;
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100%;
      width: 100%;

      // whatever icon is shown;
      [class^='icon-'] {
        width: size(2);
        height: size(2);
      }
    }
  }
}