Getting autocomplete “as you type” in search screens in the LightSwitch html client

Introduction

UPDATE 28 February 2014: THIS POST IS RUBISH. See my later article for a more decent approach.

It’s quite easy to setup in LightSwitch a textbox used for searching in a list view. Unfortunately, it’s not possible to have autocomplete ‘as you type” with live preview.

In this article I’ll present two approaches for getting this type of autocomplete. But let’s first make sure you understand clearly what I  mean with autocomplete “as you type”.

Autocomplete as you type

I created a small test application having a Country table and I created programmatically 1000 countries, each called Country xxx {where xxx goes from 0 to 999).

So, we have search box, where we can start typing. Directly when the second letter is typed, the listview starts previewing data:

image

When we further refine:

image

As you can see, this differs from the out-of-the-box behavior. The difference is a press enter click. Sounds unimportant, but for users it makes a huge difference !

 

Approach 1: Post render a normal list-view

This is the simplest approach, but is limited on the level of tweaking.

We start from a completely out-of-the-box browse screen on Countries and disable paging on the Countries query on the viewmodel.

And we hydrate the  post render method of country list:

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.BrowseCountriesNativeLS.Country_postRender = function (element, contentItem) {
    var $element = $(element);
    var unorderedList = $($("ul", $element)[0])
    unorderedList.attr("data-filter", "true");
    unorderedList.attr("data-filter-placeholder", "search countries...");

    unorderedList.on("listviewcreate", function (event, ui) {
      //we'll see if we can use this
    });

};

Pretty simple, but it works.

 

Approach 2: a custom control

We start from an even simpler screen layout:

 

As you can see, nothing on the view model. Only a rows layout with a custom control.

 

Following  render code will do the magic:

/// <reference path="../GeneratedArtifacts/viewModel.js" />

myapp.BrowseCountries.Countries_render = function (element, contentItem) {

    var control = $("<ul class='msls-listview' id='autocomplete' data-role='listview' data-inset='true' data-filter-theme='b' data-filter='true' data-filter-placeholder='Find a country...'></ul");

    control.appendTo(element);

    var ctrl = $(element).find("[data-role='listview']");

    ctrl.on("listviewbeforefilter", function (e, data) {
         var $ul = $(this),
             $input = $(data.input),
             value = $input.val(),
             html = "";
         $ul.html("");
         if (value && value.length > 1) {
             $ul.html("<li><div class='ui-loader'><span class='ui-icon ui-icon-loading'></span></div></li>");
             $ul.listview("refresh");

            contentItem.screen.details.dataWorkspace.ApplicationData.Countries
                 .filter("substringof('" + value + "', Name) eq true").execute()
                 .done(
                 function oncomplete(result) {
                     for (var i = 0; i < result.results.length; i++) {
                         html += "<li>" + result.results[i].Name + "</li>";
                     }
                     $ul.html(html);
                     $ul.listview("refresh");
                     $ul.trigger("updatelayout");
                 },
                 function onError(error) {
                     console.log("error :" + error);
                 },
                 function onProgress(line) {
                     console.log(line.Name);
                 }
                 );

        }
     });

};

 

Basically, the render method will retreive the data by asynchronously applying a filter based on the odata filter syntax (which I hate BTW). The returned data will be rendered in list items.

No magic but it works. The advantage of the custom control approach is that initially no data are loaded. The loading of the data only starts after typing the second character.

Please HTML/Jquery/javascript gurus stand up and help me to improve this approach

I’m not a Jquery (mobile) guru. So, I would really appreciate if some readers with more insight in this matter could help me to improve the rendering of the listview filter box, etc. …

It would be great if the whole look and feel would perfectly integrate in a normal LightSwitch project. Also packaging the functionality as a Jquery Mobile plugin would be a great contribution :)