1

Am Using MVC4 and I am trying to implement cascading list boxes into one of my views, I've been following this tutorial and have successfully created 2 cascading drop down boxes but I now require the same type of functionality for list boxes where the user can select multiple items.

Just to clarify a user will be able to choose a Threat from a drop down list.

Upon selecting a Threat, a list box will be populated with the associated security events of the selected Threat, here the user will be able to select multiple security events or a single security event

Upon choosing their selected security events, another list box will be populated with any controls which are associated with the selected security events.

Here is what I have so far

View Model

 public class AddNewRiskVM
    {
        public SelectList RiskTypeList { get; set; }
        public SelectList GroupMembersList { get; set; }
        public SelectList ThreatsList { get; set; }
        public SelectList SecurityEventsList { get; set; }
        public List<int> SelectedSecurityEventsIDs { get; set; }
        public SelectList ISOControlList { get; set; }
        public List<int> AssociatedIsoIDs { get; set; }
        public int ISOControlID { get; set; }

        public AddNewRiskVM()
        {
            SelectedSecurityEventsIDs = new List<int>();
            AssociatedIsoIDs  = new List<int>();
        }       
    }

Controller

public void ConfigureNewRisk(AddNewRiskVM ViewModel)
        { 
            var RiskTypes = _DBContext.RiskTypes;
            var Threats = _DBContext.Threats;

            ViewModel.RiskTypeList = new SelectList(RiskTypes, "ID", "Description");
            ViewModel.GroupMembersList = new SelectList(new List<GroupMember>(), "ID", "Name");
            ViewModel.ThreatsList = new SelectList(Threats, "ID", "Description");
            ViewModel.SecurityEventsList = new SelectList(new List<SecurityEvent>(), "ID", "Description");
            ViewModel.ISOControlList = new SelectList(new List<ISOControl>(), "ID", "Description");
        }

        public ActionResult AddNewRisk()
        {
            AddNewRiskVM ViewModel = new AddNewRiskVM();
            ConfigureNewRisk(ViewModel);

            return View(ViewModel);
        }
     public IEnumerable<ISOControl> GetISOControls(int SecurityEventID)
        {
            var QueryResults = _DBContext
                                   .SecurityEventHasISOControls
                                   .Include("SecurityEventHasISOControls.ISOControlID")
                                   .Where(x => x.SecurityEventID == SecurityEventID)
                                   .Select(x => x.ISOControl);

            return QueryResults;
        }

        public JsonResult GetJsonISOControl(int ID)
        {
            var ISOControlListT = this.GetISOControls(Convert.ToInt32(ID));
            var ISOControlList = ISOControlListT.Select(x => new SelectListItem()
            {
                Text = x.Description,
                Value = x.ID.ToString(),
            });
            return Json(ISOControlList, JsonRequestBehavior.AllowGet);
        }

Note - I have similar methods as GetISOControl & GetJsonControl which are used for The SecurityEvent

View

<div class="containeSelect">
     @using (Html.BeginForm(null, null, new { @id = string.Empty }, FormMethod.Post, new { @id = "AddNewWithSelect" }))
     {
        <h3>Add New Risk</h3>
        <fieldset>

             @Html.DropDownList("RiskType", Model.RiskTypeList, "Select Risk Type", htmlAttributes: new { @class = "CascadeInputBox", onchange = "GetMembers()"})
             @Html.DropDownList("GroupMember", Model.GroupMembersList, "Select Group Member", htmlAttributes: new {@class = "CascadeInputBox", @id = "CascadeDropDownList2"})
             @Html.DropDownList("Threats", Model.ThreatsList, "Select Threat", htmlAttributes: new { @class = "CascadeInputBox", onchange = "GetSecurityEvents()"})
             @Html.ListBoxFor(m => m.SelectedSecurityEventsIDs, Model.SecurityEventsList, htmlAttributes: new { @id = "SelectListEvent", onchange = "GetISOControls()"})
             @Html.ListBox("ISOControls", Model.ISOControlList, htmlAttributes: new { @id = "SelectListISO"})

        </fieldset>
     }

<script>
    function GetISOControls() {
        $.ajax({
            url: "@Url.Action("GetJsonISOControl", "RiskAssesment")",
            dataType: "json",
            type: "GET",
            data: { id: $("#Events").val() },
            error: function () {
            },
            beforeSend: function () {
            },
            success: function (data) {
                var items = "";
                $.each(data, function (i, item) {
                    items += "<option value=\"" + item.Value + "\">" + item.Text + "</option>";
                });
                $("#SelectListISO").html(items);
            }
        });
    }
 </script>
<script>  
    function GetSecurityEvents() {
        $.ajax({  
            url: "@Url.Action("GetJsonSecurityEvent", "RiskAssesment")", 
            dataType: "json",  
            type: "GET",  
            data: { id: $("#Threats").val() },
            error: function () {  
            },  
            beforeSend: function () {  
            },  
            success: function (data) {  
                var items = "";  
                $.each(data, function (i, item) {  
                    items += "<option value=\"" + item.Value + "\">" + item.Text + "</option>";  
                });
               $("#SelectListEvent").html(items);
            }  
        });         
    }  
 </script> 

This is the first time I've used ajax, I know I have to somehow change the line below, since in my helper method I haven't used a string name, instead I have used a linq expression, maybe that's all that is required for this to work, right now I cant see anything else but maybe am missing something?

data: { id: $("#Events").val() },

If anyone could offer any advice, especially with the ajax it would be appreciated.

Thanks in advance

1 Answer 1

1

You do not have an element with id="Events". The listbox your referring to has id="SelectedSecurityEventIDs". And because its a <select multiple> its value is an array and so you need the jQuery.param method to serialie your data. Rather than polluting your markup with behavior, I recommend using Unobtrusive Javascript so the GetISOControls script will be replaced with

var isoList = $("#SelectListISO"); // cache it
$('#SelectedSecurityEventIDs').change(function() {
    // create a serialized representation of the selected values
    var data = $.param({ id: $(this).val() }, true);

    $.ajax({
        url: "@Url.Action("GetJsonISOControl", "RiskAssesment")",
        dataType: "json",
        type: "GET",
        data: data,
        success: function (data) {
            isoList.empty();
            $.each(data, function (i, item) {
                isoList.append($('<option></option>').val(item.Value).text(item.Text));
            });
        }
    });
});

And the controller method needs to be

public JsonResult GetJsonISOControl(IEnumerable<int> ID)

because you are posting an array of values (your will need to adjust your query to suit). Note also there is no need to create a SelectList (its just sending back extra data to the client which is not used). Is should be just

var ISOControlList = ISOControlListT.Select(x => new
{
    Text = x.Description,
    Value = x.ID.ToString(),
});

Side note:

@Html.ListBox("ISOControls", Model.ISOControlList, ..)

is creating a control which has no relationship to your model (it does not have a property named ISOControls and therefore wont be bound to your model. I assume it should be

@Html.ListBoxFor(m => m.AssociatedIsoIDs, Model.ISOControlList, ..)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Stephen for your great explanation and the linked articles, they have definitely helped to shed some light on what's actually going on within the Java script block, plus everything is now working as hoped :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.