Juan Carlos Oropeza
Juan Carlos Oropeza

Reputation: 48177

How HtmlHelper know data is on the ViewBag?

I was watching a tutorial about HtmlHelper for DropDown https://www.youtube.com/watch?v=79aYSOcmpV8

Around min 8, he is reading the db to replace some hardcode values.

To pass list of Departments from the controller, store them in "ViewBag"

public ActionResult Index()
{
    // Connect to the database
    SampleDBContext db = new SampleDBContext();
    // Retrieve departments, and build SelectList
    ViewBag.Departments = new SelectList(db.Departments, "Id", "Name");

    return View();
}

Last step.

Now in the "Index" view, access Departments list from "ViewBag"

@Html.DropDownList("Departments", "Select Department") 

I dont see anything like strong type model on the view.


So how the Helper know Departments refers to a value in the ViewBag?

Upvotes: 0

Views: 411

Answers (1)

user3559349
user3559349

Reputation:

When you add a value to ViewBag, it is also added to the ViewData property of ViewContext when the view is generated. The DropDownList() overload that your using in equivalent to passing a null SelectList in

@Html.DropDownList("Departments", null, "Select Department")

in which case, internally, the helper searches the ViewData property to find a matching key which is an IEnumerable<SelectListItem> (which "Departments" is). You can see the relevant code in the private static MvcHtmlString SelectInternal() method of the source code

// If we got a null selectList, try to use ViewData to get the list of items.
if (selectList == null)
{
    selectList = htmlHelper.GetSelectData(name);
    ....
}

Note that the example in the tutorial is a poor approach, using 'magic' strings and requiring you to access the value in the POST method using Request.Form["Departments"]. A far better approach is to use a view model and strongly bind to your view model, for example

public class MyViewModel
{
    public int SelectedDepartment { get; set; }
    public IEnumerable<SelectListItem> DepartmentList { get; set; }
    ...
}

and the GET method would be

public ActionResult Create()
{
    MyViewModel model = new MyViewModel
    {
        DepartmentList = new SelectList(db.Departments, "Id", "Name");
    };
    return View(model);
}

and in the view

@model MyViewModel
....
@Html.DropDownListFor(m => m.SelectedDepartment, Model.DepartmentList, "Select Department")

and post the form back to

[HttpPost]
public ActionResult Create(MyViewModel model)

Upvotes: 2

Related Questions