Filtering Fun with JavaScript.
Ever been in a situation where you have already gathered your results from the server, but you need to do some arbitrary text searching on them? Here's a handy way to do it.
Here it is in action:
See the Pen Filtering Fun with JavaScript by Lorin Tackett (@ltackett) on CodePen.
... and here's the code:
contacts.haml
Basic iteration through all the elements.
%input.form-control{ data: { action: 'text-search' }, type: "text", placeholder: "Filter by name or location" }
.contacts
- contacts.each do |contact|
.card{ data: { element: 'item' }}
%h4= contact.name
%p= contact.address
%p= contact.citystate
contacts.scss
Simple styling for the cards.
@include 'compass';
body { padding-top: 3em; }
.form-control {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
padding: 0.75em 0.5em;
z-index: 1;
}
.contacts {
position: relative;
overflow: hidden;
padding: 0.5%;
& { font-size: 0; }
& .card { font-size: initial; }
}
.card {
@include border-radius(0.25em);
@include box-sizing(border-box);
display: inline-block;
background: #333333;
color: #ffffff;
margin: 0.5%;
padding: 2em;
width: 32.25%;
&[data-filtered=false] { display: none; }
&[data-filtered=true] { display: inline-block; }
h4, p {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.25em;
}
h4 { margin: 0 0 0.5em; }
p { margin: 0; }
}
text_search.coffee
When I was wiring it up, I chose to use data attr bindings instead of class names. Decoupling your event bindings from your markup classes is a good idea in almost every case.
# Utility function for searching by a word.
hasWordInString = (word) -> @indexOf(word) isnt -1
# Function for filtering items by an array of words
window.filterItems = ($el) ->
words = $el.val().toLowerCase()
$items = $("[data-element=item]")
# Split `text` to a space-delimited array.
# We will search by this array later.
words = words.split(" ")
# Hide all items on event.
$items.attr('data-filtered', false)
# Is the first item of `text` a non-empty string?
# Cool. Filter the items and show them.
if words[0].length > 0
# Iterate through the array of words.
# If any of those words are found in
# the `itemText`, this will return `true`.
# This tells the filter that this item
# matches the search, which then shows it.
$items = $items.filter ->
item = $(this)
return words.every(hasWordInString, item.text().toLowerCase())
return
# Show filtered items
$items.attr('data-filtered', 'true')
# Text input is empty? Show all items.
else $items.removeAttr('data-filtered')
return
# Bind actions to event handlers
$("[data-action]").each ->
$el = $(@)
action = $el.data('action')
if action == 'text-search' then $el.on 'keyup', (event) -> filterItems($el)
comments powered by Disqus