An ECMAScript 6 Search Box (Part 2)

In my previous article I set up the basic ASP.NET environment and a build environment with gulp. I also added a couple of libraries that I will need to the build environment and made sure my wwwroot directory was built and cleaned appropriately. Today I am going to create a fully ECMAScript 6 compatible Search Box based on my prior work with RequireJS and jQuery.

The ECMAScript 6 Search Box

I’ve used a lot of the same code in this class as in my jQuery extension plugin. Let’s look at it bit by bit though. I’ve created a src/js/classes directory for my work. I’ve created a MySearchBox.js Javascript file. Somewhat surprisingly, Visual Studio understood most of my ECMAScript 6 code. Hopefully Visual Studio and Web Essentials will catch up fast and provide full ECMAScript 6 intellisense soon. Let’s start with the constructor of the class:

import * as $ from 'jquery';

// Class for implementing the Search box functionality
class MySearchBox {

    // Constructor to set up the searchbox
    constructor(pElement, pOptions = {}) {
        this.clickableElement = pElement;
        // Create an options field based on the default options overridden by the provided options
        this.options = $.extend({
            searchId: MySearchBox.generateGUID(),
            bubbleClass: 'bubble'
        }, pOptions || {});

        // Make the thing that enables the search box clickable
        pElement.css({'cursor': 'pointer'}).click({ 'options': this.options }, MySearchBox.onClick);

The import statement at the top tells the compiler that I need jQuery to be the $ variable – this is going to be fairly normal as long as you have a need for jQuery. Next I’ve defined my class and my constructor. In a departure from my jQuery version I’m using the ES6 default parameters to allow the user to not pass in any options. I use the normal jQuery method of setting the defaults for jQuery plugins – I’ve just moved it inside the class.

A quick note about jQuery events. Just like in prior versions of my code, I am going to lose the context of the event, so I’m designating the event handler as a static block of code in the class. As I learn more ES6 and Javascript, I’m sure I’ll find a way to write this that doesn’t lose the context. For right now – this works.

I’ve got two methods to write – generateGUID() comes directly from my utils.js file and looks like this:

    // Utility function to return a GUID
    static generateGUID() {
        let d = new Date().getTime();
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            let r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);

Finally, we need the click-handler method onClick. Here i put a whole load of debugging statements in as well. One of the optimizations I can do later on is to strip out debugging statements for production. I’m more likely to leave debugging statements in with that functionality.

    // Click Handler to create or destroy the search box
    static onClick(evt) {
        let clickedElement = $(evt.currentTarget),
            options =,
            searchElem = $('#' + options.searchId);"MySearchBox::onClick");"evt = ", evt);"clickedElement = ", clickedElement);"searchElem = ", searchElem);

        if (searchElem.length > 0) {
            // If it's there, destroy it
  "searchElem exists - removing it");
        }"No searchElem - need to create one");
        // Calculate the ideal position for the new element
        let left = clickedElement.position().left - 22,
            top  = clickedElement.position().top + clickedElement.height() + 12,
            maxWidth = 350,
            width = ((left + maxWidth) < $(window).width()) ? maxWidth: $(window).width() - left;"left = ", left);"top = ", top);"maxWidth = ", maxWidth);"width = ", width);

        // Create the new DIV element with contents from a template
        let divElement = $(`<div id='${options.searchId}' class='${options.bubbleClass}'></div>`)
                .html("<div class='search'><input type='search' name='serch' placeholder='Search'></div>")
				    'display': 'block',
				    'position': 'absolute',
				    'left': left + 'px',
				    'top': top + 'px',
				    'width': width + 'px'
				});"Added ID=", options.searchId, " to the body: ", divElement);

        // Set the input focus to the search box
        $('input[type=search]', divElement).focus();"Focus on the search");

Finally, I need to hook this class in as a jQuery plugin:

// jQuery Interface to the class above
$.fn.searchbox = function(pOptions) {
    return $(this).each(function() {
        $(this).data('my-searchbox', new MySearchBox($(this), pOptions));

In this file I’ve used the following new elements of ECMAScript 6:

In order to get this working, I need to compile the ECMAScript 6 code into ES5 code with babel and I need to use a module loader and bootstrap code to get it loaded. Finally, I need some stuff in my HTML page to wire it up.

I need to add gulp-babel and gulp-sourcemaps to my devDependencies in my package.json file to bring in babel support for gulp. I’m also going to add requirejs as a dependency at the same time since I need a module loader. Here is my current package.json file:

    "version": "1.0.0",
    "name": "BubbleSearch",
    "private": true,
    "bin-links": true,
    "dev":  true,
    "dependencies": {
        "bootstrap": "3.3.2",
        "jquery": "2.1.3",
        "requirejs": "2.1.16"
    "devDependencies": {
        "gulp": "3.8.11",
        "del": "1.1.1",
        "merge-stream": "0.1.7",
        "gulp-babel": "4.0.0",
        "gulp-sourcemaps": "1.5.0"

In order to use RequireJS, I need to bootstrap file: src/js/init.js. This file is relatively small:

    baseUrl: '/js',
    paths: {
        'jquery': '/lib/jquery/jquery.min',
        'bootstrap': '/lib/bootstrap/js/bootstrap.min'
    shim: {
        'bootstrap': { deps: ['jquery'] }

], function ($) {
    $(document).ready(function () {

When I brought in RequireJS from NPM I noticed that it didn’t have a dist directory so I can’t add it to my libraries array. There are always exceptions to the rule. I’m going to have to deal with that separately in the Gulpfile.js with this task:

gulp.task('libraries:requirejs', function () {
    gulp.src(path.join(npmPath, 'requirejs/require.js'))
        .pipe(gulp.dest(path.join(buildPath, 'lib/requirejs')));

I also want to compile my ECMAScript 6 files and put them in my wwwroot directory. This is another task in the Gulpfile.js. I’m also going to put in a task to clean up my generated javascript files:

gulp.task('source:compile-js', function () {
    return gulp.src(['src/js/init.js', 'src/js/**/*.js'])
        .pipe(babel({ modules: "amd" }))
        .pipe(gulp.dest(path.join(buildPath, "js")));

gulp.task('source:clean-js', function (cb) {
    del([path.join(buildPath, 'js/**')], cb);

Finally I need to update the build and clean tasks in Gulpfile.js:

gulp.task('build', [

gulp.task('clean', [

As before, you can now use the build and clean tasks to generate the wwwroot area. We still have not wired up the code within the test.html file. Update the test.html file like this:

<!DOCTYPE html>
    <meta charset="utf-8">
    <title>Test Page</title>
    <link href="lib/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
    <link href="lib/bootstrap/css/bootstrap-theme.min.css" rel="stylesheet" />
                <li id="nav-appstore"><span class="glyphicon glyphicon-th"></span></li>
                <li id="nav-notifications"><span class="glyphicon glyphicon-comment"></span></li>
                <li id="nav-search"><span class="glyphicon glyphicon-search"></span></li>

    <script src="lib/requirejs/require.js" data-main="js/init"></script>

Let’s automate the running of the build and clean steps. To do this, right-click on the build task in the Task Runner Explorer and select Binding->After Build. Do the same thing for the clean task but pick the Binding->Clean option. Now you can run the project and it will automatically build your wwwroot area for you – you no longer have to right-click on Tasks->build to get the build to run – just press F6.

Before I leave, let me point out the console.


Note the line numbers on the right hand side. They refer to the line numbers in the ECMAScript 6 file – not the line numbers in the compiled Javascript. I’ve also made the function collapsible – you can click on the arrow next to MySearchBox::onClick and collapse all the debugging statements into one line.

In my next article I’ll be discussing styling of the search box and will integrate the SASS preprocessor and Pleeease into my build process. Until then, I’ve uploaded this code to my GitHub Repository for you to review. Note that it is the complete code, so check out the other articles in the series that cover everything.