Create an ASP.NET MVC Autofill Control, Part 2
In Part 2 of our autofill control, we attempt to create a transparent placeholder in an ASP.NET MVC textbox.
In Part 1, we demonstrated how to create an autofill control using HTML and simple JavaScript/jQuery.
In today's post, I dig further into how to achieve an autofill with a "permanent placeholder" as my client asked.
The Situation
The issue with this concept is the user's input will be regular text (normal text as always) and the remaining company name text (the hint) will be gray.
In a TextBox, you can't change color in mid-text. You can highlight the text as we did in the previous post.
I thought "Ok, can we change the highlight to make it look transparent and gray?" After researching this idea, I came up blank.
Strike one.
Ok, Hmm...How about?...
What if I took a label and placed it exactly under the TextBox?
That may work.
The Approach
We need to contain the label inside the autofill because we'll be using both relative and absolute positioning with CSS.
The autofill container will be relative positioning while the input will be absolute.
Our HTML will have a similar layout, but include one more DOM element: the autofill-text (in bold).
<div class="form-group"> <div class="row"> <div class="col-md-4"> @Html.Label("New Company", "New Company:") <span class="autofill"> <span class="autofill-text"></span> @Html.TextBox("CompanyPlaceholder", 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>
We want the text to be it's regular color in the textbox (black?) with the ".autofill-text" label shown below it in a gray color.
This will require some CSS for our positioning of elements.
<style> .autofill { position: relative; }
.autofill, .autofill input { background: none; display: block; padding: 5px 10px; }
.autofill .autofill-text { font-weight: normal; color: #BBB; height: 30px; font-size: 12px; line-height: 1.5; /* strictly for placement purposes */ padding-left: 1px; }
.autofill input { left: 0; position: absolute; /* strictly for placement purposes */ top: 1px; } </style>
A couple of warnings with this approach.
- The
.autofill .autofill-text
class needs to duplicate your target textbox's height, line-height, padding, font style, font weight...everything to exactly match your textbox's specifications. This text will be placed behind the textbox. I recommend using Google's Chrome DevTools, Firefox's Dev Tools, or Edges Dev Tools (all accessed using F12) to find the CSS properties of a textbox and copy them into the.autofill-text
class. - Both classes ("
.autofill .autofill-text
" and ".autofill input
") may require some tweaking to make the hinted text (.autofill-text) line up to the textbox. I've already placed some positioning comments in the CSS (/* strictly for placement purposes */).
As I mentioned, we are containing the absolute and relative positioning to a closed off DOM element. This shouldn't affect any other element on the page.
The Killing Blow
Naturally, we need JavaScript for this to work (again!).
In this post, we are only changing the autofill-text by setting the HTML inside of it.
// 2. Use a grayed out "placeholder" var company2 = $("#CompanyPlaceholder");
$(company2).delayKeyup(function () {
$(".autofill-text").html("");
var partialCompanyName = $(company2).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];
var upperLowerVendor = returnedCompany.substr(0, partialCompanyName.length);
$(company2).val(upperLowerVendor); $(".autofill-text").html(returnedCompany); } }) .fail(function () { console.log("error"); }); }, 1000);
We slice off a substring of the valid company returned based on the length of the user input and set it as the value in the textbox.
Finally, we place the company in the .autofill-text using the html(). The CSS handles the rest.
You should see the following:
But there are some UI problems I didn't anticipate.
Overlapping Characters
If someone's really fast on the keyboard and they backspace fast enough and then type a letter, the letter overlaps the hint's character making it look a little..uhh..weird.
We are using the keyup event for our delay. How can we fix this?
By simply clearing out the .autofill-text when a user presses a key.
$(company2).keypress(function () { $(".autofill-text").html(""); });
Issue resolved.
Plus it looks cleaner.
Losing Focus Loses It's Value (in a manner of speaking)
When a user types a partial company name and presses tab to move forward with their choice, the textbox would keep only the partial text in the textbox.
I was racking my brain trying to determine if I should use a "if this key...do this."
But then I thought, don't fall into the trap of detecting the tab key. While it can be done, there is a simpler way to fix this.
Use the onBlur event when the user leaves the textbox.
$(company2).blur(function () { var value = $(".autofill-text").html(); if (value !== "") { $(company2).val(value); } });
Grab the value from the autofill-text and place it into the company textbox when focus is lost.
Conclusion
I've been trying to come up with a different way to achieve this in CSS and JavaScript. This seems to be the only way to achieve this feat.
If someone has a better approach, I would appreciate any input (no pun intended) or feedback regarding this technique.
So far, it seems to be working across one of my applications.
Is there a better approach? Post your comments below and let's discuss.