简体   繁体   中英

Select multiple terms within one listbox asp c#

I would like to select a term from the dropdown and then select a color or value from the same term. For example, I want to select "Account Executive" and then select "red". Is there a jquery library already out there? Is it possible? It can also be a dropdown rather than the color.

在此输入图像描述

This is how I populate the dropdown c#

  DataSet dsRoles = obj.ds("Role");
  ddlRole.DataSource = dsRoles ;
  ddlRole.DataTextField = "Term";
  ddlRole.DataValueField = "Term";
  ddlRole.DataBind();
  ddlRole.Items.Insert(0, new ListItem("== Select 1 Term ==", ""));

Asp

<asp:ListBox ID="ddlRole" AutoPostBack="false" runat="server" SelectionMode="Multiple"> 

Unfortunately I do not know of anything out of the box that has that control. One of the more popular multi select jquery libraries out there is select2. You could override the js event for it to behave in the manner you are looking to accomplish. I am not sure how extensible this would be without some refactoring but here is a walk through on how to do it on a single select.

Link to CDN for select2: https://select2.org/getting-started/installation

First setup your basic select element

<select id="tag" style="width: 50%" multiple="multiple"></select>

The the fun begins in js

We will need to keep track of our selected values

    var collectionArray = [];

Next is out initial array to feed into our select2 control whereas id is the unique identifier of the position, simple text is the value you want to dispaly when selected, text is the html value in the dropdown

The text element has a your color blocks and each one has a on click element to pass the id and a numeric representation of the color into a js function. This should be blown out further but keeping it simple for demo

    var data = [
        { id: 0, simpleText:'Account Executive',  text: '<div style="display:block; min-height:30px; cursor:default;"><div style="float:left;">Account Executive</div><div style="float:right;"><table><tr><td class="tableSelect tableSelectRed" onclick="select2Override(0,0)"></td><td class="tableSelect tableSelectOrange" onclick="select2Override(0,1)"></td><td class="tableSelect tableSelectGreen"onclick="select2Override(0,2)"></td></tr></table></div></div>' },
        { id: 1,simpleText:'Account Management',  text: '<div style="display:block; min-height:30px; cursor:default;"><div style="float:left;">Account Management</div><div style="float:right;"><table><tr><td class="tableSelect tableSelectRed" onclick="select2Override(1,0)"></td><td class="tableSelect tableSelectOrange"onclick="select2Override(1,1)"></td><td class="tableSelect tableSelectGreen" onclick="select2Override(1,2)"></td></tr></table></div></div>' }];

Next we initialize our select2 object with our data array. We will need to override the selecting and unselecting functions and handle these on our own

$("#tag").select2({
        data: data,
        //these options are telling it to use html from the text element. They are required or else it will just generate your html as text
        templateResult: function (d) { return $(d.text); },
        templateSelection: function (d) { return $(d.text); },
        tags: true

    }).on("select2:selecting", function (e) {
        // make sure we are on the list and not within input box
        //this is overriding the default selection event of select2, we will hadle that in our own onclick function based upon the color box they selected
        if (e.params.args.originalEvent.currentTarget.nodeName === 'LI') {
            e.preventDefault();
        }
    }
    ).on('select2:unselecting', function (e) {
        //we are injecting another method here when the object is unselected. We want to remove it from our master list to prevent duplicate inputs on our add function
        removeFromList(e.params.args.data.id);
    });

We will need to manually handle the remove from our select list and make sure our master collection stays up to date

    function removeFromList(id) {
        //actual remove from the selected list
        $('#tag option[value=' + id + ']').remove();
        //actual remove from the master collection to prevent dups
        collectionArray = collectionArray.filter(entry => entry.tagID != id)
    }

Our main mover function for selection is next. We first need to check if the item already exists in our main collection (we dont want dups). If it does NOT then we need to give it a unique ID for later reference in our master list. We will find the max value from our current select list to make sure are not duplicating then inject the new value into our select list making sure it is marked as selected and alos into our master collection array:

    function select2Override(id, color) {
        //our override function for when anyone selects one of the color boxes

        //first check if it is already in our master list, if so then dont add a dup, remove it!
        var doesExistsAlready = collectionArray.filter(entry => entry.type === id && entry.color === color);
        if (doesExistsAlready.length != 0) {
            for (var i = 0; i < doesExistsAlready.length; i++) {
                removeFromList(doesExistsAlready[i].tagID);
            }

        } else {
            //its not found in our master list 
            //we need to get a unique if to accompy this entry, fund the highest existing value in the current list and add 1
            var lastID = findMaxValue($('#tag')) + 1;

            //push it to our master list
            collectionArray.push({ "type": id, "color": color, "tagID": lastID });

            //get the selected value from our initial list so we can pull out the "simple text" to display
            var check = $.grep(data, function (obj) { return obj.id === id; })[0];

            //decorate our selection with a color depending on what they selected
            var colorDisplay;
            switch(color) {
              case 0:
                    colorDisplay = "red";
                break;
              case 1:
                colorDisplay =  "orange"
                break;
              case 2:
                    colorDisplay =  "green";
                break;
            }
            //prep our new select option with our new color, simple text and unique id and set to selected
            var newOption = new Option('<div style="color:' + colorDisplay + ';display:inline;">' + check.simpleText + '</div>', lastID, true, true);

            //append it to our list and call our change method so js reacts to the change
            $('#tag').append(newOption).trigger('change');
        }
    }

Here is our JS function to make sure we have a unique ID from the select list items that already exists.

    //function to find the max value from our already existing list
    function findMaxValue(element) {
        var maxValue = undefined;
        $('option', element).each(function() {
            var val = $(this).attr('value');
            val = parseInt(val, 10);
            if (maxValue === undefined || maxValue < val) {
                maxValue = val;
            }
        });
        return maxValue;
    }

Lastly, we need to override some css so that items that we inject into our list are not shown for further selection. Luckily we can grab the disabled attributes that select2 uses for default behavior when an item is selected:

    .select2-container--default .select2-results__option[aria-selected=true] {
        display: none;
    }

Also, some css to make my hacked together html on the select element look semi presentable:

    .tableSelect {
        min-width: 20px;
        height: 20px;
        border: 1px solid #fff;
        cursor: pointer;
        margin-bottom: 10px;
    }

    .tableSelectGreen {
        background-color: green;
    }

    .tableSelectRed {
        background-color: red;
    }

    .tableSelectOrange {
        background-color: orange;
    }

    blockMe{
        min-height:20px;
        min-width:20px;
    }

Putting it all together:

  //this is where we will keep track of our selected values var collectionArray = []; //this is out initial array to feed into our select2 control //whereas id is the unique identifier of the position, simple text is the value you want to dispaly when selected, text is the html value in the dropdown //the text element has a your color blocks and each one has a on click element to pass the id and a numeric representation of the color into a js function. This blwon out further but keeping it simple for demo var data = [ { id: 0, simpleText:'Account Executive', text: '<div style="display:block; min-height:30px; cursor:default;"><div style="float:left;">Account Executive</div><div style="float:right;"><table><tr><td class="tableSelect tableSelectRed" onclick="select2Override(0,0)"></td><td class="tableSelect tableSelectOrange" onclick="select2Override(0,1)"></td><td class="tableSelect tableSelectGreen"onclick="select2Override(0,2)"></td></tr></table></div></div>' }, { id: 1,simpleText:'Account Management', text: '<div style="display:block; min-height:30px; cursor:default;"><div style="float:left;">Account Management</div><div style="float:right;"><table><tr><td class="tableSelect tableSelectRed" onclick="select2Override(1,0)"></td><td class="tableSelect tableSelectOrange"onclick="select2Override(1,1)"></td><td class="tableSelect tableSelectGreen" onclick="select2Override(1,2)"></td></tr></table></div></div>' }]; //here we initialize our select2 object with our data array. $("#tag").select2({ data: data, //these options are telling it to use html from the text element. They are required or else it will just generate your html as text templateResult: function (d) { return $(d.text); }, templateSelection: function (d) { return $(d.text); }, tags: true }).on("select2:selecting", function (e) { // make sure we are on the list and not within input box //this is overriding the default selection event of select2, we will hadle that in our own onclick function based upon the color box they selected if (e.params.args.originalEvent.currentTarget.nodeName === 'LI') { e.preventDefault(); } } ).on('select2:unselecting', function (e) { //we are injecting another method here when the object is unselected. We want to remove it from our master list to prevent duplicate inputs on our add function removeFromList(e.params.args.data.id); }); function removeFromList(id) { //actual remove from the selected list $('#tag option[value=' + id + ']').remove(); //actual remove from the master collection to prevent dups collectionArray = collectionArray.filter(entry => entry.tagID != id) } function select2Override(id, color) { //our override function for when anyone selects one of the color boxes //first check if it is already in our master list, if so then dont add a dup, remove it! var doesExistsAlready = collectionArray.filter(entry => entry.type === id && entry.color === color); if (doesExistsAlready.length != 0) { for (var i = 0; i < doesExistsAlready.length; i++) { removeFromList(doesExistsAlready[i].tagID); } } else { //its not found in our master list //we need to get a unique if to accompy this entry, fund the highest existing value in the current list and add 1 var lastID = findMaxValue($('#tag')) + 1; //push it to our master list collectionArray.push({ "type": id, "color": color, "tagID": lastID }); //get the selected value from our initial list so we can pull out the "simple text" to display var check = $.grep(data, function (obj) { return obj.id === id; })[0]; //decorate our selection with a color depending on what they selected var colorDisplay; switch(color) { case 0: colorDisplay = "red"; break; case 1: colorDisplay = "orange" break; case 2: colorDisplay = "green"; break; } //prep our new select option with our new color, simple text and unique id and set to selected var newOption = new Option('<div style="color:' + colorDisplay + ';display:inline;">' + check.simpleText + '</div>', lastID, true, true); //append it to our list and call our change method so js reacts to the change $('#tag').append(newOption).trigger('change'); } } //function to find the max value from our already existing list function findMaxValue(element) { var maxValue = undefined; $('option', element).each(function() { var val = $(this).attr('value'); val = parseInt(val, 10); if (maxValue === undefined || maxValue < val) { maxValue = val; } }); return maxValue; } 
  .tableSelect { min-width: 20px; height: 20px; border: 1px solid #fff; cursor: pointer; margin-bottom: 10px; } .tableSelectGreen { background-color: green; } .tableSelectRed { background-color: red; } .tableSelectOrange { background-color: orange; } blockMe{ min-height:20px; min-width:20px; } .select2-container--default .select2-results__option[aria-selected=true] { display: none; } 
 <link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.9/css/select2.min.css" rel="stylesheet" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.9/js/select2.min.js"></script> <select id="tag" style="width: 50%" multiple="multiple"></select> 

As I know, one of the best solutions to you is grouping options. I have implemented it like below, but I am not in CSS, so you should add some classes to change positions and colors (I think it's not hard too much).

Sample classes

public class Role
{
    public Role(string name, int value)
    {
        Name = name;
        Value = value;
        SubRoles = new List<SubRole>();
    }

    public string Name { get; set; }
    public int Value { get; set; }
    public List<SubRole> SubRoles { get; set; }


    public enum SubRoleType
    {
        Red = 1,
        Orange = 2,
        Green = 3
    }
}

public class SubRole
{
    public string Name { get; set; }
    public int Value { get; set; }

    public SubRole(string name, int value)
    {
        Name = name;
        Value = value;
    }
}

Code Behind

    protected void Page_Load(object sender, EventArgs e)
    {
        List<Role> roles = new List<Role>();
        Role accountantRole = new Role("Accountant", 1);
        accountantRole.SubRoles.Add(new SubRole(SubRoleType.Red.ToString(), (int)SubRoleType.Red));
        accountantRole.SubRoles.Add(new SubRole(SubRoleType.Orange.ToString(), (int)SubRoleType.Green));
        accountantRole.SubRoles.Add(new SubRole(SubRoleType.Green.ToString(), (int)SubRoleType.Orange));
        roles.Add(accountantRole);

        Role managmentRole = new Role("Accountant Managment", 2);
        managmentRole.SubRoles.Add(new SubRole(SubRoleType.Red.ToString(), (int)SubRoleType.Red));
        managmentRole.SubRoles.Add(new SubRole(SubRoleType.Orange.ToString(), (int)SubRoleType.Green));
        managmentRole.SubRoles.Add(new SubRole(SubRoleType.Green.ToString(), (int)SubRoleType.Orange));
        roles.Add(managmentRole);

        foreach (var role in roles)
            AddRoleToDropDownList(ddlRole, role);          
    }

    private void AddRoleToDropDownList(DropDownList list, Role role)
    {
        foreach (var subRole in role.SubRoles)
        {
            ListItem item = new ListItem(subRole.Name, subRole.Name);
            item.Attributes["data-category"] = role.Name;
            list.Items.Add(item);
        }
    }    

Markup

<asp:DropDownList runat="server" ID="ddlRole" />

<script>
    var groups = {};
    $("select option[data-category]").each(function () {
        groups[$.trim($(this).attr("data-category"))] = true;
    });
    $.each(groups, function (c) {
        $("select option[data-category='" + c + "']").wrapAll('<optgroup label="' + c + '">');
    });
</script>

yes there are quite some a java and css magic that can help you do this. Have a look at this one from MDB , or from Telerik

There are however not that hard to make, you need

  1. A Div that you populate with your choices, any html tag will do as long as you can click it. make clicking it change the CSS to a specific class and register the click (and unclick in a list/form for post-back later)

  2. Place the div on the item that is supposed to be the drop down and unhide it

  3. Make the pop-up / dopdown go away when clicking on the "OK","Cancel", "escape key", "enter key"

  4. Onhide of the dip post back your choices to process the change

Have a look at jquery, will have samples for each of these i think

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM