2

I am trying to convert a poorly developed C# web app to MVC2, and I am having difficulties trying to build a cascading dropdown. This is the code:

public IEnumerable<SelectListItem> SchoolList
    {
        get
        {
            DataTable dt = ClassModels.GetSchools();
            List<SelectListItem> list = new List<SelectListItem>();
            foreach (DataRow row in dt.Rows)
            {
                list.Add(new SelectListItem
                {
                    Text = Convert.ToString(row["School"]),
                    Value = Convert.ToString(row["SID"]),
                });
            }
            return list;
        }
    }

    public IEnumerable<SelectListItem> DepartmentList
    {
        get
        {
            DataTable dt = DomData.GetDepartments(this is where the selected SID goes)
            List<SelectListItem> list = new List<SelectListItem>();
            foreach (DataRow row in dt.Rows)
            {
                list.Add(new SelectListItem
                {
                    Text = Convert.ToString(row["Department"]),
                    Value = Convert.ToString(row["DID"]),
                });
            }
            return list;
        }
    }

This is the model for the Departments

public static DataTable GetDepartments(int id)
    {
        string sql = string.Format(@"SELECT d.department, d.did
            FROM dept d
            WHERE d.did IN (SELECT DISTINCT(DID) FROM CDS WHERE SID = '{0}')
            ORDER BY department", id);

        DataTable db_table = new DataTable("departments");
        SqlDataAdapter db_adapter = new SqlDataAdapter(sql, iau_conxn_string);

        db_adapter.Fill(db_table);
        //ddl_dep.DataSource = db_table;
        //ddl_dep.DataValueField = "did";
        //ddl_dep.DataTextField = "department";
        //ddl_dep.DataBind();
        return db_table;
    }

Sadly, I have to do this without AJAX or jQuery.

Marcus Nizza
  • 71
  • 1
  • 6
  • 1
    Without AJAX and jQuery? And how do you expect that to happen? Can you use javascript at least? Without javascript you will never be able to subscribe to the `onchange` event of the first ddl. So if you cannot use javascript at all you will need an additional button that the user needs to click after making the selection in the first ddl in order to submit the form to the server and rebind the second ddl. So? – Darin Dimitrov Aug 08 '12 at 16:32
  • That's exactly my issue.. I suppose I could use JS. The only reason I cannot use AJAX/jQuery is because the client has strict specs. If I were to use JS, how would that work? – Marcus Nizza Aug 08 '12 at 16:37
  • So pure JS (without any JS library) and without AJAX? Is that your requirement? – Darin Dimitrov Aug 08 '12 at 16:37
  • 1
    What did you do to your client, that they hate you so? – GalacticCowboy Aug 08 '12 at 16:41
  • I think their previous developer was a dummy, and they just despise programmers now. – Marcus Nizza Aug 08 '12 at 16:42
  • In this day and age, it's almost impossible to find a web site that doesn't use javascript. Even google does, although they spend a lot of time and effort making it degrade gracefully. – Erik Funkenbusch Aug 08 '12 at 16:55
  • @MarcusNizza In webforms the autopostback functionality is achieved via javascript. It's unfortunate that you can not use jQuery or AJAX. It makes me sad that the client would not want to implement the most robust and easy solution. – Chuck Conway Aug 08 '12 at 17:00
  • @all, the OP said that he cannot use AJAX and jQuery. But he can use javascript. Of course all this is unfortunate but let's leave that to the stupidity of the OP's client and not make a big story out of it. I think the OP realizes perfectly fine that this is crap and hopefully he will try to persuade his client but that's really not that important to the question itself. – Darin Dimitrov Aug 08 '12 at 17:01

1 Answers1

1

Since you cannot use AJAX but only pure javascript you could subscribe to the onchange event of the first dropdown and then submit the form in order to populate the second dropdown.

But before putting this into action let's start by defining a view model. In my example I will obviously remove all the noise that was present in your question (things like DataTables and data access specific code and simply hardcode the values so that the answer be more general, so simply replace those hardcoded values with a call to your data access method):

public class MyViewModel
{
    public MyViewModel()
    {
        Departments = Enumerable.Empty<SelectListItem>();
    }

    public int? SchoolId { get; set; }
    public IEnumerable<SelectListItem> SchoolList
    {
        get
        {
            // TODO: fetch the schools from a DB or something
            return new[]
            {
                new SelectListItem { Value = "1", Text = "school 1" },
                new SelectListItem { Value = "2", Text = "school 2" },
            };
        }
    }

    public int? DepartmentId { get; set; }
    public IEnumerable<SelectListItem> Departments { get; set; }
}

then a controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }

    [HttpPost]
    public ActionResult Departments(MyViewModel model)
    {
        // TODO: use model.SchoolId to fetch the corresponding departments
        // from your database or something
        model.Departments = new[]
        {
            new SelectListItem { Value = "1", Text = "department 1 for school id " + model.SchoolId },
            new SelectListItem { Value = "2", Text = "department 2 for school id " + model.SchoolId },
            new SelectListItem { Value = "3", Text = "department 3 for school id " + model.SchoolId },
        };
        return View("Index", model);
    }
}

and finally a view:

<%@ Page 
    Language="C#" 
    Inherits="System.Web.Mvc.ViewPage<MyViewModel>" 
%>
<% using (Html.BeginForm(null, null, FormMethod.Post, new { id = "myform", data_departments_url = Url.Action("Departments") })) { %>
    <div>
        <%= Html.LabelFor(x => x.SchoolId) %>
        <%= Html.DropDownListFor(
            x => x.SchoolId, 
            Model.SchoolList, 
            "-- School --",
            new { id = "school" }
        ) %>
    </div>

    <div>
        <%= Html.LabelFor(x => x.DepartmentId) %>
        <%= Html.DropDownListFor(
            x => x.DepartmentId, 
            Model.Departments,
            "-- Department --"
        ) %>
    </div>
<% } %>

and the last bit is of course javascript to subscribe to the onchange event of the first dropdown and submit the form to the server in order to populate the second dropdown:

window.onload = function () {
    document.getElementById('school').onchange = function () {
        if (this.value) {
            var form = document.getElementById('myform');
            form.action = form.getAttribute('data-departments-url');
            form.submit();
        }
    };
};

And for those that don't have the same constraints as you and can use AJAX and jQuery take a look at the following answer: https://stackoverflow.com/a/4459084/29407

Community
  • 1
  • 1
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Okay, I am sure this is going to work, and thanks a lot.. Though, I have one question.. Do you have any advice on how to enumerate a datatable? – Marcus Nizza Aug 08 '12 at 17:22
  • Scratch that, I just made a helper method to convert the datatables.. You're code worked great Dimitrov, thanks a lot. – Marcus Nizza Aug 08 '12 at 17:38