Example: Filter a Set of Existing Items on a Page

This example demonstrates how to use AutoCompleteBase alone, without a list widget, to filter a set of existing items on a page. While this is a departure from the typical autocomplete interaction pattern, AutoCompleteBase is flexible enough to provide an excellent solution without any unnecessary overhead.

To filter the list of delicious pies, type a descriptive term into the input field below. For example, to see only apple pies, type "apple", or for all fruit pies, type "fruit".

HTML

Note: be sure to add the yui3-skin-sam classname to the page's <body> element or to a parent element of the widget in order to apply the default CSS skin. See Understanding Skinning.

<div id="demo" class="yui3-skin-sam"> <!-- You need this skin class -->
  <label for="ac-input">Filter by:</label><br>
  <input id="ac-input" type="text">

  <ul id="photos">
    <li class="photo" data-tags="apple, fruit">
      <a href="http://www.flickr.com/photos/wonko/5213328415/in/photostream/">
        <img src="http://farm6.static.flickr.com/5002/5213328415_4cf3aa583f_m.jpg" alt="Apple pie">
      </a>
    </li>

    <li class="photo" data-tags="pecan">
      <a href="http://www.flickr.com/photos/wonko/5213327801/in/photostream/">
        <img src="http://farm6.static.flickr.com/5208/5213327801_1e62145da1_m.jpg" alt="Pecan pie">
      </a>
    </li>

    <li class="photo" data-tags="maple custard">
      <a href="http://www.flickr.com/photos/wonko/5213920818/in/photostream/">
        <img src="http://farm6.static.flickr.com/5245/5213920818_bf7cd599c3_m.jpg" alt="Maple custard pie">
      </a>
    </li>

    <li class="photo" data-tags="pumpkin">
      <a href="http://www.flickr.com/photos/wonko/5213912956/in/photostream/">
        <img src="http://farm6.static.flickr.com/5049/5213912956_7cba11aa01_m.jpg" alt="Pumpkin pie">
      </a>
    </li>

    <li class="photo" data-tags="turkey, pot pie, carrots, meat, savory">
      <a href="http://www.flickr.com/photos/wonko/2055852065/in/photostream/">
        <img src="http://farm3.static.flickr.com/2330/2055852065_d9a7d56650_m.jpg" alt="Turkey pot pie">
      </a>
    </li>

    <li class="photo" data-tags="cherry, hearts, fruit">
      <a href="http://www.flickr.com/photos/wonko/100174720/in/photostream/">
        <img src="http://farm1.static.flickr.com/34/100174720_dad453636d_m.jpg" alt="Cherry pie with two hearts on top">
      </a>
    </li>

    <li class="photo" data-tags="lattice, sour cherry, fruit">
      <a href="http://www.flickr.com/photos/faerye/4839675135/in/photostream/">
        <img src="http://farm5.static.flickr.com/4083/4839675135_fb5e88da3d_m.jpg" alt="Lattice-top sour cherry pie">
      </a>
    </li>

    <li class="photo" data-tags="chocolate, cream, cinnamon, meringue, christmas, tree">
      <a href="http://www.flickr.com/photos/faerye/4283875981/">
        <img src="http://farm5.static.flickr.com/4029/4283875981_faaccb9089_m.jpg" alt="Chocolate cream pie with cinnamon meringue">
      </a>
    </li>

    <li class="photo" data-tags="strawberry, chiffon, chocolate, wafer, fruit">
      <a href="http://www.flickr.com/photos/faerye/4592482821/">
        <img src="http://farm2.static.flickr.com/1070/4592482821_925ba97e60_m.jpg" alt="Strawberry chiffon pie with chocolate wafer crust">
      </a>
    </li>

    <li class="photo" data-tags="key lime, whipped cream, graham cracker, slice, fruit">
      <a href="http://www.flickr.com/photos/faerye/3492566166/">
        <img src="http://farm4.static.flickr.com/3413/3492566166_0fd62e0d43_m.jpg" alt="Key lime pie with graham cracker crust">
      </a>
    </li>

    <li class="photo" data-tags="lattice top, apple, fruit">
      <a href="http://www.flickr.com/photos/faerye/3394679580/">
        <img src="http://farm4.static.flickr.com/3569/3394679580_8b08c46fe6_m.jpg" alt="Lattice top apple pie">
      </a>
    </li>
  </ul>
</div>

CSS

#photos {
  border: 1px solid #cfcfcf;
  list-style: none;
  margin: 1.5em 0 0;
  padding: 6px;
}

#photos li {
  display: inline-block;
  list-style: none;

  /* fake inline-block for IE<8 */
  zoom: 1;
  *display: inline;
}

#photos .empty { font-style: italic; }

#photos .photo {
  margin: 5px;
  text-align: center;
  width: 240px;
}

#photos .photo img {
  border: 1px solid #000;
  vertical-align: top;
}

#photos .hidden { display: none; }

JavaScript

YUI().use('autocomplete-base', 'autocomplete-filters', function (Y) {
  // Create a custom PieFilter class that extends AutoCompleteBase.
  var PieFilter = Y.Base.create('pieFilter', Y.Base, [Y.AutoCompleteBase], {
    initializer: function () {
      this._bindUIACBase();
      this._syncUIACBase();
    }
  }),

  // Create and configure an instance of the PieFilter class.
  filter = new PieFilter({
    inputNode: '#ac-input',
    minQueryLength: 0,
    queryDelay: 0,

    // Run an immediately-invoked function that returns an array of results to
    // be used for each query, based on the photos on the page. Since the list
    // of photos remains static, this saves time by not gathering the results
    // for each query.
    //
    // If the list of results were not static, we could simply set the source
    // to the function itself rather than invoking the function immediately,
    // and it would then run on every query.
    source: (function () {
      var results = [];

      // Build an array of results containing each photo in the list.
      Y.all('#photos > .photo').each(function (node) {
        results.push({
          node: node,
          tags: node.getAttribute('data-tags')
        });
      });

      return results;
    }()), // <-- Note the parens. This invokes the function immediately.
          //     Remove these to invoke the function on every query instead.

    // Specify that the "tags" property of each result object contains the text
    // to filter on.
    resultTextLocator: 'tags',

    // Use a result filter to filter the photo results based on their tags.
    resultFilters: 'phraseMatch'
  });

  // Subscribe to the "results" event and update photo visibility based on
  // whether or not they were included in the list of results.
  filter.on('results', function (e) {
    // First hide all the photos.
    Y.all('#photos > .photo').addClass('hidden');

    // Then unhide the ones that are in the current result list.
    Y.Array.each(e.results, function (result) {
      result.raw.node.removeClass('hidden');
    });
  });
});

Complete Example Source

<style scoped>
  #photos {
    border: 1px solid #cfcfcf;
    list-style: none;
    margin: 1.5em 0 0;
    padding: 6px;
  }

  #photos li {
    display: inline-block;
    list-style: none;

    /* fake inline-block for IE<8 */
    zoom: 1;
    *display: inline;
  }

  #photos .empty { font-style: italic; }

  #photos .photo {
    margin: 5px;
    text-align: center;
    width: 210px;
  }

  #photos .photo img {
    border: 1px solid #000;
    vertical-align: top;
    width: 210px;
  }

  #photos .hidden { display: none; }
</style>

<div id="demo" class="yui3-skin-sam"> <!-- You need this skin class -->
  <label for="ac-input">Filter by:</label><br>
  <input id="ac-input" type="text">

  <ul id="photos">
    <li class="photo" data-tags="apple, fruit">
      <a href="http://www.flickr.com/photos/wonko/5213328415/in/photostream/">
        <img src="http://farm6.static.flickr.com/5002/5213328415_4cf3aa583f_m.jpg" alt="Apple pie">
      </a>
    </li>

    <li class="photo" data-tags="pecan">
      <a href="http://www.flickr.com/photos/wonko/5213327801/in/photostream/">
        <img src="http://farm6.static.flickr.com/5208/5213327801_1e62145da1_m.jpg" alt="Pecan pie">
      </a>
    </li>

    <li class="photo" data-tags="maple custard">
      <a href="http://www.flickr.com/photos/wonko/5213920818/in/photostream/">
        <img src="http://farm6.static.flickr.com/5245/5213920818_bf7cd599c3_m.jpg" alt="Maple custard pie">
      </a>
    </li>

    <li class="photo" data-tags="pumpkin">
      <a href="http://www.flickr.com/photos/wonko/5213912956/in/photostream/">
        <img src="http://farm6.static.flickr.com/5049/5213912956_7cba11aa01_m.jpg" alt="Pumpkin pie">
      </a>
    </li>

    <li class="photo" data-tags="turkey, pot pie, carrots, meat, savory">
      <a href="http://www.flickr.com/photos/wonko/2055852065/in/photostream/">
        <img src="http://farm3.static.flickr.com/2330/2055852065_d9a7d56650_m.jpg" alt="Turkey pot pie">
      </a>
    </li>

    <li class="photo" data-tags="cherry, hearts, fruit">
      <a href="http://www.flickr.com/photos/wonko/100174720/in/photostream/">
        <img src="http://farm1.static.flickr.com/34/100174720_dad453636d_m.jpg" alt="Cherry pie with two hearts on top">
      </a>
    </li>

    <li class="photo" data-tags="lattice, sour cherry, fruit">
      <a href="http://www.flickr.com/photos/faerye/4839675135/in/photostream/">
        <img src="http://farm5.static.flickr.com/4083/4839675135_fb5e88da3d_m.jpg" alt="Lattice-top sour cherry pie">
      </a>
    </li>

    <li class="photo" data-tags="chocolate, cream, cinnamon, meringue, christmas, tree">
      <a href="http://www.flickr.com/photos/faerye/4283875981/">
        <img src="http://farm5.static.flickr.com/4029/4283875981_faaccb9089_m.jpg" alt="Chocolate cream pie with cinnamon meringue">
      </a>
    </li>

    <li class="photo" data-tags="strawberry, chiffon, chocolate, wafer, fruit">
      <a href="http://www.flickr.com/photos/faerye/4592482821/">
        <img src="http://farm2.static.flickr.com/1070/4592482821_925ba97e60_m.jpg" alt="Strawberry chiffon pie with chocolate wafer crust">
      </a>
    </li>

    <li class="photo" data-tags="key lime, whipped cream, graham cracker, slice, fruit">
      <a href="http://www.flickr.com/photos/faerye/3492566166/">
        <img src="http://farm4.static.flickr.com/3413/3492566166_0fd62e0d43_m.jpg" alt="Key lime pie with graham cracker crust">
      </a>
    </li>

    <li class="photo" data-tags="lattice top, apple, fruit">
      <a href="http://www.flickr.com/photos/faerye/3394679580/">
        <img src="http://farm4.static.flickr.com/3569/3394679580_8b08c46fe6_m.jpg" alt="Lattice top apple pie">
      </a>
    </li>
  </ul>
</div>

<script>
YUI().use('autocomplete-base', 'autocomplete-filters', function (Y) {
  // Create a custom PieFilter class that extends AutoCompleteBase.
  var PieFilter = Y.Base.create('pieFilter', Y.Base, [Y.AutoCompleteBase], {
    initializer: function () {
      this._bindUIACBase();
      this._syncUIACBase();
    }
  }),

  // Create and configure an instance of the PieFilter class.
  filter = new PieFilter({
    inputNode: '#ac-input',
    minQueryLength: 0,
    queryDelay: 0,

    // Run an immediately-invoked function that returns an array of results to
    // be used for each query, based on the photos on the page. Since the list
    // of photos remains static, this saves time by not gathering the results
    // for each query.
    //
    // If the list of results were not static, we could simply set the source
    // to the function itself rather than invoking the function immediately,
    // and it would then run on every query.
    source: (function () {
      var results = [];

      // Build an array of results containing each photo in the list.
      Y.all('#photos > .photo').each(function (node) {
        results.push({
          node: node,
          tags: node.getAttribute('data-tags')
        });
      });

      return results;
    }()), // <-- Note the parens. This invokes the function immediately.
          //     Remove these to invoke the function on every query instead.

    // Specify that the "tags" property of each result object contains the text
    // to filter on.
    resultTextLocator: 'tags',

    // Use a result filter to filter the photo results based on their tags.
    resultFilters: 'phraseMatch'
  });

  // Subscribe to the "results" event and update photo visibility based on
  // whether or not they were included in the list of results.
  filter.on('results', function (e) {
    // First hide all the photos.
    Y.all('#photos > .photo').addClass('hidden');

    // Then unhide the ones that are in the current result list.
    Y.Array.each(e.results, function (result) {
      result.raw.node.removeClass('hidden');
    });
  });
});
</script>