Sunday, September 20, 2015

filters in jquery

A year or two ago I made a "cheat sheet" for the chords my band plays. I wanted something that would be easy to manipulate via my iPhone, when I need a quick peek. To put it mildly, I screwed up the UI- and especially what it took to add a new song. I liked the idea of having all the data in the body of the DOM, rather than storing it in, say, JSON and building the page, but I made a dog's breakfast of it...

The core function (which is still there) was alright... tapping the title of a song (an h3 tag) opened up the notes associated with it (in a pre tag). The thing was, I linked the h3 and the pre tag via an id naming convention... so for each song header I had to come up with a shortname id, and then pre section it was with had to have the same id followed by "_". Bleh!

My new approach is to wrap each h3/pre pair in a div. Duhhr- that's just being neat and clean. So the code for responding to a click on a header is:
function clickTitle(){
  var header = $(this);
  header.parent().find("pre").toggle();
}
and I can ignore IDs entirely.

I also realized that, despite ordering the headers alphabetically, it wasn't super-easy to locate a song - like I woudn't know if "When the Saints Go Marching in" be under "When" or "Saints", or would "Just a Closer Walk with Thee" be under "Just" or "Closer" etc... and the mobile safari find function isn't particularly smooth to move in this case.

When it looked like my next big project was going to be in Angular I thought about rebuilding the app using Angular, and in particular the nice loop with filter... some kind of ngRepeat with 
item in items | filter:searchText
would do it, except again it implies an external data rather than DOM-data driven design. (I assume there's some way of doing a more DOM-centric version in Angular, but I'm not adept to know what it looks like... maybe I'll ask my Angular-loving buddy/guru.)

Anyway, jQuery has a decent ".contains()" filter for its selector chains... except it's not case insensitive.  But, the font of all wisdom StackOverflow had the solution for that:
jQuery.expr[':'].Contains = function(a,i,m){
     return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase())>=0;
};

Adds a "Contains" (vs "contains") that is case-insensitive. So combining that with a  .on('input') on the input box and it worked pretty well. (And I really like the "verb" centric approach, of setting up an easy to understand event handler in jQuery, vs the "noun" centric approach of setting a loop and filter that automagically updates in Angular.)


No comments:

Post a Comment