Click here to Skip to main content
15,881,588 members
Articles / Programming Languages / Typescript
Tip/Trick

Typescript Type Ahead Binding and Filter with Knockout.js and Underscore.js

Rate me:
Please Sign up or sign in to vote.
4.50/5 (5 votes)
29 Nov 2016CPOL2 min read 12.9K   4   1
I did two versions, one with a simple text dump to a span as HTML, and the other to filter contents of a drop down list (select). This article only contains the simpler one. I hope to add the other one depending on how this is received and if I can host code samples demos somewhere.

Introduction

If you're looking for examples using knockout.js and underscore.js together, this should be a good one. The resulting UI is nothing sexy.

A couple of potential annoying gotchas:

The example uses Typscript syntax because that is what I use in my current dev environment.

Please forgive me for not having a hosted demo, I'm coming up to speed on how and where to do that.

Background

While searching for "typeahead" examples, I realized I already did this with knockout.js and underscore.js.

Uses a knockout.js observable with the input filter text, an observable array to hold initialized data, a computed observable with chained underscore.js filter and sort to do the type ahead filtering magic.

For my purposes I'm assuming some basic knowledge and experience with using knockout.js and underscore.js.

Using the Code

A quick typescript class to use:

JavaScript
class myDataModel
  {
    Name = '';
    Type = '';
    DATE: Date = null;
    constructor(pname, ptype, pdate:Date) 
    {
      this.Name = pname;
      this.Type = ptype;
      this.DATE = pdate;
    }
  }

And a quick data mock-up to use.

JavaScript
placeholderData = [
      { Name: 'Bob T. Turner', Type: "M", DATE: new Date('Jan 03 1964') },
      { Name: 'Sarah S. Wilson', Type: "F", DATE: new Date('Apr 16 1956') },
      { Name: 'Frederick R. Flintock', Type: "M", DATE: new Date('Dec 23 1974') },
      { Name: 'Joey P. Ponder', Type: "M", DATE: new Date('Jun 01 1963') },
      { Name: 'Alice C. Reston', Type: "M", DATE: new Date('Aug 28 2000') }
    ];

The Knockout.js observables, including a computed observable which filters and sorts based on UI input.

I will further explain the use of Knockout observables and the Underscore chain() below.

JavaScript
dataFilter = ko.observable('');
modelArray = ko.observableArray(<Array<myDataModel>>[]);

computedHtmlResult = ko.computed(() =>
{
  var filterText = this.dataFilter();
  var baseList = this.modelArray();

  if (!filterText)
    return '';
  else
   var vfilteredSearch =   _(baseList)
      .chain()
      .filter((pmodel) => {
         return (pmodel.Name.toLowerCase()).indexOf(filterText.toLowerCase()) !== -1;
      })
      .sortBy((pfilteredmodel) => {
        return pfilteredmodel.Name;
      })
    .value();

   var vreturnValue = '';

   _.each(vfilteredSearch, (pfsmodel) => {
     var vdateText = pfsmodel.DATE.toLocaleDateString('en-US');
     vreturnValue += pfsmodel.Name + ' ' +
     pfsmodel.Type + ' ' + vdateText + '<br>';
   });

  return vreturnValue;
});

HTML

With Knockout.js binding is accomplished with "data-bind="textInput: dataFilter "...".

HTML
<input type="text" id="dev-settings-res-scratchdiv" 
data-bind="textInput: dataFilter " 
class="input-xxlarge"/>

<span data-bind="html: computedHtmlResult "> </span>

Very clean and simple.

Back to Typescript.

The Knockout.js computed observable computedHtmlResult contains the important type-ahead intelligence: (if you are not used to underscore.js functional chains, this may not be clear at first, but I will explain more).

If there is no filter text input, we just return:

JavaScript
if (!filterText) return '';

Filter the list of models into a new list of models (vfilteredSearch) to only include those where the name contains the filter text:

JavaScript
var vfilteredSearch = _(baseList)

Chain the filter and sort.

JavaScript
.chain()

Filter the "scratch" models to only include what we want. I chose to use toLowerCase to make it case insensitive.

JavaScript
.filter((pmodel) => { return (pmodel.Name.toLowerCase()).indexOf(filterText.toLowerCase()) !== -1; })

Sort by name and add the filtered models to the new filtered array:

JavaScript
.sortBy((pfilteredmodel) => { return pfilteredmodel.Name; }) .value();

Now vfilteredSearch contains the filtered models.

Let's create some simple HTML text to display in the UI. Not very sexy, but demonstrates the concept quite well:

JavaScript
var vreturnValue = '';

_.each(vfilteredSearch, (pfsmodel) => 
{ 
var vdateText = pfsmodel.DATE.toLocaleDateString('en-US'); 
vreturnValue += pfsmodel.Name + ' ' + pfsmodel.Type + ' ' + vdateText + '<br>'; 
});

return vreturnValue;

The return value now contains simple HTML text for only the filtered models, this will be displayed in the span.

If all works well, the text should be blank until a user inputs something in the text input.

An input of "b" or "B" should result in only "Bob T. Turner..." displayed.

An input of "o" or "O" should show all the data.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Currently working with a team developing our next generation web application with a Rest API in C# targeting a single page MVC HTML5 AVL app using Typescript, Knockout, Underscore, Bootstrap, Font-Awesome and Moment.

The backend/server is software-as-a-service (SaaS) currently connected to an SQL DB, but we are looking into utilizing Redis more and future development with Cassandra technologies.

This is quite a fast paced, dynamic project keeping me busy and challenged with new ways of coordinating different tasks and goals, not to mention shifting from my more comfortable OOP C# background into the world of functional programming in the wonderful world of web applications. Let me catch my breath.....

Comments and Discussions

 
GeneralMy vote of 5 Pin
Farhad Reza2-Dec-16 6:13
Farhad Reza2-Dec-16 6:13 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.