Jay
Jay

Reputation: 910

DropDownListFor issue with selected values

I'm fairly new (okay well very new) to MVC. I'm trying to create a cascading dropdown list, where I can also preselect a value.

I've spent most of the day on this, but not really got very far. I've looked at a lot of resources, though the most useful were:

http://www.deliveron.com/blog/post/Creating-a-Cascading-Dropdown-in-ASPnet-MVC-3-and-jQuery.aspx - I used this heavily and got my own version of it working, I couldn't get there example working.

http://odetocode.com/blogs/scott/archive/2013/03/11/dropdownlistfor-with-asp-net-mvc.aspx - general oversite.

MVC DropDownList SelectedValue not displaying correctly - There is what appears to be a really good example here, following the view-model method, but for some reason it didn't seem to work for me.

What I've got so far is:

Model:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;

    namespace BLPrototype.Models
    {
        public class VehicleModels
        {
            public List<vehicle_make> getVehicleMakeList()
            {
                using (var db = new BLEntities())
                {
                    List<vehicle_make> vmk = db.vehicle_make.OrderBy(r => r.vmk_name).ToList();
                    return vmk;
                }
            }

            public List<vehicle_group> getVehicleModelList(string vmk_id)
            {
                using (var db = new BLEntities())
                {
                    List<vehicle_group> vmo = db.vehicle_group.Where(v => v.vg_vmk_id == vmk_id).OrderBy(r => r.vg_name).ToList();

                    return vmo;
                }
            }

        }

        public class vmCatalogue1
        {
            public string Title { get; set; }

            [Display(Name = "Select a make")]
            public IEnumerable<SelectListItem> selectVehicleMake { get; set; }
            [Display(Name = "Select a model")]
            public IEnumerable<SelectListItem> selectVehicleModel { get; set; }

        }

    }

Controller:

using BLPrototype.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace BLPrototype.Controllers
{
    public class TestController : Controller
    {
        //
        // GET: /Test/

        public ActionResult Index()
        {
            VehicleModels vm = new VehicleModels();
            var model = new vmCatalogue1();

            //Which is better and why?
            model.selectVehicleMake = vm.getVehicleMakeList().Select(x => new SelectListItem { Value = x.vmk_id, Text = x.vmk_name });
            //model.selectVehicleMake = new SelectList(vm.getVehicleMakeList(), "vmk_id", "vmk_name");

            model.selectVehicleModel = new SelectList(vm.getVehicleModelList(""), "vg_id", "vg_name");

            model.Title = "Title goes here";

            return View(model);
        }

        VehicleModels vm = new VehicleModels();

        [HttpPost]
        public ActionResult Makes()
        {
            var makes = vm.getVehicleMakeList();

            return Json(new SelectList(makes, "vmk_id", "vmk_name"));
        }

        [HttpPost]
        public ActionResult Models(string vmk_id)
        {
            var models = vm.getVehicleModelList(vmk_id);

            return Json(new SelectList(models, "vg_id", "vg_Name"));
        }

    }
}

View:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@Model.Title    </title>

   <script src="~/Scripts/jquery-1.7.1.min.js"></script>

    <script type="text/javascript">
        function getModels(vmk_id) {

            $.ajax({
                url: "@Url.Action("Models")",
                data: { vmk_id: vmk_id },
            dataType: "json",
            type: "POST",
            error: function () {
                alert("An error occurred.");
                errorHandler("error1");
            },
            success: function (data) {
                var items = "";
                $.each(data, function (i, item) {
                    items += "<option value=\"" + item.Value + "\">" + item.Text + "</option>";
                });

                $("#selectVehicleModel").html(items);
            }
        });
    }

    $(document).ready(function () {
        $("#selectVehicleMake").change(function () {
            getModels($("#selectVehicleMake").val());
        });
    });


</script>

</head>
<body>
    <div>

@model BLPrototype.Models.vmCatalogue1
@using (Html.BeginForm())
{        
    <div class="editor-label">
        @Html.LabelFor(m => m.selectVehicleMake)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(model => model.selectVehicleMake, Model.selectVehicleMake, "Please select")

    </div>

    <div class="editor-label">
        @Html.LabelFor(m => m.selectVehicleModel)
    </div>
    <div class="editor-field">
        @Html.DropDownListFor(m => m.selectVehicleModel,  Model.selectVehicleModel, new { style = "width: 150px" })
    </div>    

}
</body>
</html>

The above example shows the cascading dropdowns. I've seen lots of different ways of populating a dropdownlistfor, I would like to do it via a View-Model. I'm really not sure which is the best way. Some examples seem to show just a list, some a list of selectlistitems and others just a selectlist. Could someone please tell me the difference and what is the 'better' way to do it... I know it often depends upon the application.

I would also like to be able to preselect a Make if I wish, I've seen some examples where you include the ID in various ways, and others by tagging it on to the end of the select list. None of them seem to work.

Also the Model shouldn't really show unless the make has been selected. Would I do this via CSS or another method?

Finally I've put the "Please Select" at the end of the make, so it shows. This doesn't seem like a great way of doing this. Could you please point me in the right direction?

Thank you for your time and I'm sorry for so many stupid noobish questions!

Thanks

Jay

Upvotes: 0

Views: 2106

Answers (2)

Jay
Jay

Reputation: 910

I finally found the solution that I was after. I'll post it here in case anyone find this post in the future with similar errors.

Model:

public class VehicleModels
{
    public List<vehicle_make> getVehicleMakeList()
    {
        using (var db = new BLEntities())
        {
            List<vehicle_make> vmk = db.vehicle_make.OrderBy(r => r.vmk_name).ToList();
            return vmk;
        }
    }

    public List<vehicle_group> getVehicleModelList(string vmk_id)
    {
        using (var db = new BLEntities())
        {
            List<vehicle_group> vmo = db.vehicle_group.Where(v => v.vg_vmk_id == vmk_id).OrderBy(r => r.vg_name).ToList();

            return vmo;
        }
    }

}

public class vmCatalogue3
{
    public string Title { get; set; }

    public string selectedMakeId { get; set; }
    public string SelectTopLine { get; set; }

    [Display(Name = "Select a make")]
    public SelectList selectVehicleMake { get; set; }

    [Display(Name = "Select a model")]
    public SelectList selectVehicleModel { get; set; }

}

Controller:

        public ActionResult Index()
    {
        VehicleModels vm = new VehicleModels();
        var model = new vmCatalogue3();

        model.selectedMakeId = "870";
        model.SelectTopLine = "Please Select";

        model.selectVehicleMake = new SelectList(vm.getVehicleMakeList(), "vmk_id", "vmk_name");
        model.selectVehicleModel = new SelectList(vm.getVehicleModelList(""), "vg_id", "vg_name");

        return View(model);            
    }

View:

        @Html.DropDownListFor(m => m.selectedMakeId, Model.selectVehicleMake, Model.SelectTopLine )

Hope that helps someone!

Upvotes: 0

Graeme Wicksted
Graeme Wicksted

Reputation: 1815

A list of SelectListItems is more explicit and gives you a Selected property but it's more geared at multi-select lists and you no longer have access to the original list if your view requires it elsewhere.

Take a look at SelectList. It might work better for you in some cases. You can obtain one like this:

myList.ToSelectList("ID", "Description")

or

new SelectList(myList, "ID", "Description)

Add:

data-placeholder="Please Select"

in the same object that contains your "style = ..." if you want a placeholder until an option is selected.

Upvotes: 1

Related Questions