jordan.baucke
jordan.baucke

Reputation: 4328

Partial ViewModels, Controllers, in Razor

Trying to get my ducks in a row with MVC3 + Razor!

I finally understand the concept of a 'View-Model' to wrap my entity classes and tailor them to a View.

Now I'm assembling a page with partial views representing different elements necessary to the page (such as drop down lists, forms, etc.) each of these will be represented by a 'View-Model' that maps to an entity class and back to my database.

First I am trying to create a partial view representing a component that is a drop-down list of elements in the database, that when selected will render another partial view, etc.

I just can't put together why I can't generate this drop-down list, and once I do how the main 'controller' maps all this together?

In short I'm curious - does each partial view need a controller even if it's based on a strongly typed model?

Breaking it down:

My Entity Model-View Wrapper (getting all the elements available from the database

*Updated* - to a working example now, note I don't think I was asking the right question before, but this will give you an idea of what I was trying to accomplish! Next step is to move all these operations 'off' the controller (and populate them in the models default constructor, for ease of use later).

CharactersListViewModel.cs

Going to move avoid the 'View Model' for now until I get a little more comfortable

Creating a partial view that displays a drop down list with the Characters' ID as a value, and name as the text, create strongly-typed view, partial view

controller for main-page in section:

HistoryController.cs

public class HistoryController : Controller
{
public ActionResult Index()
    {
        var list = new List<SelectListItem>();

        using (var _database = new fff_newEntities())
        {
            foreach(Character c in (from c in _database.Characters select c)){
                list.Add(new SelectListItem(){Text = c.CharacterName, Value = c.Id.ToString()});
            }
        }
        ViewBag.Clients = list;
    }
}

//
// GET: /History/Details/5

public ActionResult Details(int id)
{
    return View();
}

//
// GET: /History/Create

public ActionResult Create()
{
    return View();
} 

//
// POST: /History/Create

[HttpPost]
public ActionResult Create(FormCollection collection)
{
    try
    {
        // TODO: Add insert logic here

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

//
// GET: /History/Edit/5

public ActionResult Edit(int id)
{
    return View();
}

//
// POST: /History/Edit/5

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    try
    {
        // TODO: Add update logic here

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

public ActionResult Delete(int id)
{
    return View();
}

//
// POST: /History/Delete/5

[HttpPost]
public ActionResult Delete(int id, FormCollection collection)
{
    try
    {
        // TODO: Add delete logic here

        return RedirectToAction("Index");
    }
    catch
    {
        return View();
    }
}

The index to display the whole page including the partial component (my drop down list)

index.cshtml:

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

@Html.DropDownListFor(x => x.CurrentCharacterId, (IEnumerable<SelectListItem>)ViewBag.Clients);

On the last line here, @Html.Action(...) where do I actually create the drop-down list?


Sorry if this seems trivial but I can't wrap my head around it and I really want to learn MVC3 + Razor correctly!

Upvotes: 2

Views: 2539

Answers (1)

Chad Moran
Chad Moran

Reputation: 12854

A partial view is meant to abstract out some HTML/View Logic so that it can be re-used either in multiple places or for repeating (looping).

Though you can have an action that maps to the partial and if the partial in question does some explicit data access this might be the way to go but if you're just passing down all the data it needs from the controller itself then - no, you don't need a Controller/Action for it.

Since you're doing some explicit data access I would probably make an action for it...

[ChildActionOnly]
public ActionResult Characters()
{
    using (var _database = new entities())
    {
        CharactersViewModel viewModel = new CharactersViewModel();
        viewModel.Characters = _database.Characters.ToDictionary(c => c.Id, c => c.CharacterName);
        return PartialView(viewModel);
    }

}

In your view...

@Html.Action("Characters")

Of course there's nothing wrong with the way you're doing it but I find having it map to an action can make things easier down the road if you ever wanted to retrieve the HTML from this rendered partial view via an ajax request or something of the sort.

Notes:

  • Try to wrap your entity context object in a using so it can dispose of the connection.
  • You can use ToDictionary to select your dictionary directly from the query scope.

Upvotes: 2

Related Questions