In all cases, the search was localized to data we were displaying in a table or grid view (user selectable). Search filters were very much context sensitive. For each page, we define a list of columns that text search applies to (and mostly all columns were specified). We also used the query string in the URL to specify filters, so filters became book-markable.
As I write this, we’re finalizing the 4.1 console, which is the second release of the new code-base. In planning for version 4.2, we decided we’d like to revisit the faceted search we tried before. The widget we had used required backbone and had no desire to introduce that into an Angular application. I also surveyed other search widgets and didn’t find anything that matched that level of functionality and UX. The decision was made to develop our own Angular widget. We have a feature branch on github
How We Built It
Our console uses Chameleon templates for basic DOM structure and SASS for styling on top of Foundation. We started by creating a widget template which defined the magic search layout. It is decorated with a single foundation element to make it full-width as well as many Angular attributes. The Angular controller is what primarily drives the functionality of the search. A foundation dropdown menu is used to display search facets and value lists. Angular’s ng-repeat is used to render selected facets and items on the dropdown. The controller simply maintains lists of these things which are displayed as needed.
How to Use It
To actually use the magic search, you must initialize the controller with a list of facets in JSON and a list of filter keys (which are the columns used for text filtering). The magic search bar emits events when search actions are performed. An event called “searchUpdated” is emitted with a query string when filter facets are changed. An event called “textSearch” is emitted when text search changes. Live text filtering is supported by emitting this event for each character typed in the search input which does not match a facet.
The application can choose what to do with those 2 events. In our case, we use an XHR call to populate our tables. When the “searchUpdated” event is received a new XHR call is made using the query string. This causes a server-side fetch using the new filter values. Our application responds to the “textSearch” event by live filtering the existing list using the filter keys to inspect the objects that make up the list.
We paid a lot of attention to usability in our design. I worked with Jenny Loza to refine all of the user interaction. The user is initially presented with a blank search bar and some placeholder text. Upon clicking anywhere in the search bar, the list of facets is presented and focus is set for text input. The user may select a facet with the mouse or type. If they type and the text matches any text in the facets, the list of facets will be filtered (and matching text bolded). This lets the user use a few mouse clicks to filter items, or continue entirely with the keyboard. If the user chooses the keyboard, typing and tabbing will get them through as many facets as they wish to select (including text search). Alternatively, a user may select facets and values entirely with the mouse (excluding text search). Each facet can be removed by clicking a small X in the facet box. The entire search bar can be cleared by selecting an X to the far right. We chose not to support edit-in-place for existing facets since it is very simple to remove and add facets.
The magic search bar allows multiple facets and those are combined to reduce the set of results (using “and”). If the user selects multiple values for a single facet, those results are combined (using “or”). We find this very intuitive.
How Your Project Might Use It
I recognize that not everybody will use Foundation, or the same server-side templating (or even SASS). Here are some ways you could approach re-use in some form. In place of Foundation, you could use Bootstrap dropdowns. They use the same DOM structure as Foundation’s and similar activation, so this would be an easy switch. Note that the “hideMenu()” function in the Angular controller uses a Foundation call to close the dropdown, so that would need to be replaced as well.
Our reliance on a server-side template is very minimal. Two places insert hrefs for resources (css and js files). The other 2 template references are to send initialization values to the Angular controller. You could replace those fairly easily in your own application.
The last thing is SASS. We check in the generated css file, so you could simply use that instead of our .scss file. The only external reference our .scss file uses is a dark grey color used more widely in our application. Additionally, our application defines an item-list and item class which are used for facet display. Those can be found as a SASS mix-in here. It’s likely there are other classes in the widget that were re-used either from our application or Foundation’s own styles. I’ll try to document any further exceptions. Please notice we use 2 SVG icons from Foundation, fi-filter and fi-x.
This feature is still in development, though we think there isn’t much left to change. I do expect to find bugs which we’ll fix in the 4.2 development process. The code can be viewed in the Pull Request where you can also comment. The key files are magic_search.pt, magic_search.js and magic_search.scss. There is a ticket which we use to track this feature. It includes a list of test criteria that we’ll use to create functional tests, and it should give you a better idea of the capabilities built into this widget. Feel free to contact me with any comments, suggestions, concerns or otherwise.