Create an ASP.NET MVC AutoFill Control, Part 1

Everyone needs a little help when data entry requires some validation. Today, we present a way to give the user some data hints based on their input.

Written by Jonathan "JD" Danylko • Last Updated: • MVC •
A pothole on the road

In a recent project, I was asked to create a textbox with a "permanent placeholder."

A whaaaaa?

So I decided to follow up and ask what they meant by a permanent placeholder.

"You know...so users could receive a hint when they didn't know the correct name of a company."

"As they type, it shows a possible company name IN the textbox."

After searching, I found this example from Geoff Graham on CSS Tricks. This is exactly what they were talking about, but it didn't help.

Autofill Example

See the first name? They type the first letter and the suggestion displays the remaining letters as highlighted text.

The only thing it did was present me with the functionality of what I needed.

The animated GIF was the end goal, but HOW to do it was the dilemma.

Requirements for Autofill

Let's examine how we want this textbox to function.

  1. As they start typing a company name, they may stop to think about the spelling and require a hint.
  2. We should check the database for a partial company name.
  3. Display the suggestion with the remaining letters highlighted or grayed out in the textbox.
  4. Once they are satisfied with their input, they click tab to move to the next field and their company name is accepted.

1, 2, and 4 isn't hard at all. 3 is the problem.

Why?

If we wanted to go with the grayed out text instead of highlighted text, there isn't a way in a textbox to display text in one color for the input and the remaining suggestion in a different color.

Highlighting text is probably the better way to accomplish this, but we'll cross that gray bridge when we get to it.

Overview

First, we need a textbox.

@using (Html.BeginForm())
{
    <div class="form-group">
        <div class="row">
            <div class="col-md-4">
                @Html.Label("Company", "Company:")
                <span class="autofill">
                    @Html.TextBox("CompanyTextBox", String.Empty, new
                    {
                        @class = "form-control input-sm"
                    })
                </span>
                <p class="help-block">Enter the company name (i.e. Apple, Microsoft).</p>
            </div>
        </div>
    </div>
}

Boom! Done!

Make the Call!

Next, we need an API to retrieve our one company based on input. I created a Services controller with a fake database call (you can modify it as you see fit).

I added a new item (Web API Controller Class) called ServicesController.

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;

namespace AutofillDemo {     [Route("api/[controller]")]     public class ServicesController : Controller     {         // GET api/<controller>/5         [HttpGet("{id}")]         public List<string> Get(string id)         {             var partialCompanyName = id;
            // Create a repository to access your database here.             // For now, we'll create a small list              //   of companies for demonstration purposes.             var list = new List<string>             {                 "Apple",                 "Microsoft",                 "Google",                 "MicroCenter",                 "Microtek",                 "MicroSystems"             };
            var company = list.OrderBy(e => e).FirstOrDefault(e =>                  e.StartsWith(partialCompanyName));
            // if company is null, use an empty string.             // Else, use the company. :-)             return new List<string> { company ?? "" };         }     } }

I removed the additional HTTP verbs from the API since we don't need them at this time.

Since we have our web service built, you can test it out by running the app and typing http://localhost:<port>/api/Services/Micro into your browser. Our service should return back "MicroCenter".

Perfect!

Some [JavaScript] Assembly Required 

Now that we have our HTML and web service in place, we require JavaScript to make the magic happen.

One of our requirements is we need to give the user enough time to finish typing. Once they stop, give them a second or two to think about it.

For this functionality, we need to execute a function after a certain delay.

We also need a function to highlight (or select) the remaining characters so we can continue typing as the hints keep coming.

$.fn.delayKeyup = function (n, t) {
    var i = 0;
    return $(this).keyup(function () {
            clearTimeout(i);
            i = setTimeout(n, t);
        }),
        $(this)
};

$.fn.selectRange = function (start, end) {     return this.each(function () {         if (this.setSelectionRange) {             this.focus();             this.setSelectionRange(start, end);         } else if (this.createTextRange) {             var range = this.createTextRange();             range.collapse(true);             range.moveEnd('character', end);             range.moveStart('character', start);             range.select();         }     }); };

Of course, you need jQuery to make these functions work.

The selectRange checks to see which browser we're using with the if statement.

Let's set up our events to use these functions.

$(function() {

    var company = $("#CompanyTextBox");
    $(company).delayKeyup(function() {
var partialCompanyName = $(company).val();
        // if there's nothing there, don't do anything.         if (partialCompanyName.length === 0) {             return false;         }
        // grab company names based on the partial         $.getJSON("/api/Services/" + partialCompanyName)             .done(function(data) {                 if (data) {                     var returnedCompany = data[0];
                    // Remaining highlighted characters                     $(company).val(returnedCompany);                     $(company).selectRange(partialCompanyName.length,                         returnedCompany.length);                 }             })             .fail(function() {                 console.log("error");             });      }
,
 1000); });

After grabbing the user input, we check to see if it's empty. If so, stop what you're doing and return false.

After validating input, we make the request to return the company name through our API.

We set the returned company name in the textbox and set the selected range of characters based on the user's input.

The 1000 at the bottom is for a 1-second timeout. Set it at your discretion, but don't make them wait too long.

Conclusion

While we could use suggestion dropdowns, I felt this was more of a challenge to offer hints to users without the need to click a dropdown.

This particular technique got me thinking -- could we do something by graying out the highlighted characters (as mentioned at the beginning of this post) and making them more transparent like a placeholder?

How could it be done? I've got an idea so stay tuned (Head over to Part 2)

Do you think you know how to do the transparent placeholder? Would we need CSS? Post your comments below and let's discuss.

ASP.NET 8 Best Practices on Amazon

ASP.NET 8 Best Practices by Jonathan Danylko


Reviewed as a "comprehensive guide" and a "roadmap to excellence" with over 120 Best Practices for ASP.NET Core 8, Jonathan's first book by Packt Publishing explores proven techniques for every phase of the SDLC.

Learn industry-standard concepts to improve your coding, debugging, and deployment of ASP.NET Core websites.

Order now on Amazon.com button

Picture of Jonathan "JD" Danylko

Jonathan "JD" Danylko is an author, web architect, and entrepreneur who's been programming for over 30 years. He's developed websites for small, medium, and Fortune 500 companies since 1996.

He currently works at Insight Enterprises as an Architect.

When asked what he likes to do in his spare time, he replies, "I like to write and I like to code. I also like to write about code."

comments powered by Disqus