DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Securing Your Software Supply Chain with JFrog and Azure
Register Today

Trending

  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Decoding eBPF Observability: How eBPF Transforms Observability as We Know It
  • Stack in Data Structures
  • Understanding the Role of ERP Systems in Modern Software Development

Trending

  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Decoding eBPF Observability: How eBPF Transforms Observability as We Know It
  • Stack in Data Structures
  • Understanding the Role of ERP Systems in Modern Software Development
  1. DZone
  2. Data Engineering
  3. Databases
  4. Creating a Multi-Column Dropdown in ASP.NET MVC

Creating a Multi-Column Dropdown in ASP.NET MVC

In this post, a seasoned web developer takes us through the process of using Bootstrap and JavaScript alongside ASP.NET MVC to create a grid inside a drop-down.

Jonathan Danylko user avatar by
Jonathan Danylko
·
Jan. 14, 18 · Tutorial
Like (4)
Save
Tweet
Share
17.87K Views

Join the DZone community and get the full member experience.

Join For Free

After my ultimate drop-down series, I've had a couple readers ask how to create a multi-column drop-down, or place a grid inside a drop-down.

I know I talked about Drop-downs in Grids, but what about Grids in Dropdowns?

While you can use an unordered list (UL) to create your dropdown as we did in the Suggestion Dropdown from the series, I feel using the table tags is a better approach and avoids the CSS "acrobatics."

Also, keep in mind, since the suggestion dropdown is so similar to the grid, we'll be using that page and modifying it to meet out grid-y needs.

There are very subtle differences between these two routines and I'll cover as much as I can while updating the GitHub repo.

So let's dive in.

Preparing the Grid

Since we're using a table, we need to provide as much static HTML as possible so we aren't creating HUGE amounts of HTML in our JavaScript.

In our table placeholder, we replace the UL with our TABLE tag in the HTML:

@using (Html.BeginForm("GridDropdown", "Home", FormMethod.Post, new { @class = "suggestion-dropdown form-horizontal" }))
{
    <div class="form-group">
        @Html.Label("SearchLabel", "Cars: ", new { @class = "col-sm-1 control-label" })
        <div class="col-sm-4">
            @Html.TextBox("SearchTerm", string.Empty, new { @class = "search-term form-control" })
            <div class="suggestions hidden">
                <table class="table table-condensed table-striped suggest-grid">
                    <tbody></tbody>
                </table>
            </div>
        </div>
    </div>
}

We only want the essentials for our grid dropdown. If you want to add headers (THEAD) or footers (TFOOT), then this is place to do it, NOT in the JavaScript.

Stylin' the Grid

For you Bootstrap users out there, I'm pretty sure you noticed the Bootstrap classes for the table.

As I mentioned before, there are subtle styles we'll apply to this control.

<style>
    .suggestions {
        border: 1px solid #CCC;
        background-color: #FFF;
        width: 300px;
        z-index: 1;
        position: absolute;
        top: 30px;
        left: 15px
    }

    .suggest-grid tr.active td { background-color: #777 !important; color: #FFF }

</style>

Since I've added table-striped to the table, it was hard to see the active item in the list when we moved from row to row.

I added the background-color to be a little more obvious to the user. If you want a different color, this is the place to change the grid's selected color and background.

Finally, the JavaScript

It's surprising this JavaScript is so small and does so much.

if you are unsure about certain parts, I'll refer you to the Suggestion Dropdown post.

$(function() {

    var getSelectedValue = function() {
        var activeRow = $("tr.active");
        var firstColumn = $("td:nth-child(1)", activeRow).text();
        var secondColumn = $("td:nth-child(2)", activeRow).text();
        var entry = firstColumn + " (" + secondColumn + ")";
        return entry;
    }

    $("#SearchTerm")
        .on("focusout", function(e) {
            $(".suggestions").addClass("hidden");
        })
        .on("keyup keypress",
        function(e) {
            var active = $("tr.active", ".suggest-grid");
            if (e.which === 27) {
                $(".suggestions").addClass("hidden");
            } else if (e.which === 40) {
                if (active.length > 0) {
                    var next = $(active).next();
                    $(active).removeClass("active");
                    $(next).addClass("active");
                } else {
                    $("tr:first", ".suggest-grid").addClass("active");
                }
            } else if (e.which === 38) {
                if (active.length > 0) {
                    var previous = $(active).prev();
                    $(active).removeClass("active");
                    $(previous).addClass("active");
                } else {
                    $("tr:last", ".suggest-grid").addClass("active");
                }
            } else if (e.which === 13) {
                e.preventDefault();
                var selectedValue = getSelectedValue();
                $(this).val(selectedValue);
                $(".suggestions").addClass("hidden");
                return false;
            } else {
                // We have a good value w/ no special keys.
                var value = $("#SearchTerm").val();
                if (value === "") {
                    $(".suggestions").addClass("hidden");
                } else {
                    var uri = "/api/search/for/" + value;

                    $(".suggestions").removeClass("hidden");

                    $.getJSON(uri)
                        .done(function (data) {
                            var grid = $(".suggest-grid");
                            $("tbody", grid).empty();
                            $.each(data,
                                function (key, value) {
                                    var row =
                                        "<td>" + value.Make + "</td>" +
                                        "<td>" + value.Model + "</td>";
                                    $("tbody", grid).append($("<tr></tr>").html(row));
                                    // On mouse click, set the value.

                                    $("tr", grid).on("click",
                                        function (e) {
                                            e.preventDefault();
                                            // this = the row (tr)
                                            // Grabs the first column's value.
                                            var selectedValue = getSelectedValue();
                                            $(".search-term").val(selectedValue);
                                            $(".suggestions").addClass("hidden");
                                        });
                                });
                        });
                }
            }
        });
});

Let's examine the changes.

Starting at the top, since we have two places to accept values (when a user hits enter or clicks a row), I decided to create a getSelectedValue function.

This getSelectedValue function will populate the textbox with what you want. I decided to go with "<Make> (<Model>)" as my final input.

Next, we work on the #SearchTerm textbox.

I added an onFocusOut to the control so when they leave the textbox, the suggestions drop-down is removed (hidden).

In the suggestion dropdown, we set an LI with an ".active" class. This code is no different. Instead, we set a TR to ".active" and it functions the exact same way.

If everything falls through to the bottom, we clear the table's rows ($("tbody",grid).empty()), make the JSON call to the API, build the row if we have results, and attach an onClick event to each row.

Conclusion

In today's post, we've taken the suggestion dropdown code and modified it slightly to display grids using tables instead of single list items from unordered lists.

You can take this code and expand on it by:

  • Adding images to the columns.
  • Using IDs in a hidden table column to place into a hidden field when a record is selected.
  • Building multi-line records.

With such little amount of code to create your own custom dropdowns, the ability to attach JavaScript to a simple control can expand the possibilities to your end-users.

Are there other JavaScript custom controls you'd like to see built? Was this built properly? Post your comments below and let's discuss.

ASP.NET MVC Database ASP.NET

Published at DZone with permission of Jonathan Danylko, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Building a Flask Web Application With Docker: A Step-by-Step Guide
  • Decoding eBPF Observability: How eBPF Transforms Observability as We Know It
  • Stack in Data Structures
  • Understanding the Role of ERP Systems in Modern Software Development

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: