Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get data from a foreach partial view in razorview

I am new to MVC3 and C#.

Here is my current model

@model Reports.ViewModels.ContentViewModel
<div>Total Hours: </div>

foreach (var user in Model.Users.ToList()) {
   @Html.Partial("_DirectReports", user)
}

This is working great, I then have HTML in these partial view that renders everything I want using another @model. The problem is I want to add all the data together.

I want to create a var outside the foreach The foreach inserts data into the var and return it after the foreach is complete like so

@model Reports.ViewModels.ContentViewModel

@{var Total = 0}
foreach (var user in Model.Users.ToList()) {
   @Html.Partial("_DirectReports", user)
   //@Total is assigned a value in the partial view
}

<div>Total Hours: @Total</div>

If this is possible that would be great thks

like image 802
Outcast Avatar asked Dec 20 '22 17:12

Outcast


1 Answers

You're going down a slippery slope here by mixing logic and your view together. MVC is designed to reduce the coupling between the different layers (the model, the view and the controller) in order to make the code easier to maintain and easier to test, amongst other things.

So let's try to clean that up a bit. Firstly, Total is a piece of data and that means it should be a part of the model:

public class ContentViewModel 
{
    public List<User> Users { get; set; }
    public int TotalHours
    {
        get
        {
            return Users.Sum(u => u.Hours); // Assuming User has an Hours property
        }
    }
}

The controller should then be handling the creation of the model and giving it data. Something like this:

public ActionResult Index()
{
    ContentViewModel viewModel = new ContentViewModel();
    viewModel.Users = db.Users.ToList();

    return View(viewModel);
}

Now that you have the data you need, you can cut down on a lot of the logic you're currently using in the view (such as the use of the foreach and the Total var):

@model Reports.ViewModels.ContentViewModel

@Html.DisplayFor(m => m.Users)

<div>Total Hours: @Model.TotalHours</div>

Html.DisplayFor and Html.EditorFor use what are called display/editor templates and they will automatically loop over collections for you, rendering a template for each item. In order to take advantage of this for ContentViewModel, you need to create a display template. To do this, you need to create a folder under where the view is, and name it DisplayTemplates. For example, if your view is ~/Views/Home/Index.cshtml, you need to create the folder: ~/Views/Home/DisplayTemplates.

Right-click that folder to add a new view. In the dialog box that appears, you want to make a strongly-typed view, selecting the type you want to pass to the template (in my example, User is the type and not List<User>), make it a partial view and make sure to give it the same name as the type (again, User). Once you have your template, you can use the HTML helpers just as you would in a normal view. Something like this:

@model Models.User

@Html.LabelFor(m => m.Name)
@Html.DisplayFor(m => m.Name)

Now you have things broken up into manageable chunks. If you'd like more information on using display/editor templates, I'd highly suggest reading Brad Wilson's article series on the subject. Even though it was written for MVC 2, it still applies.

like image 72
John H Avatar answered Dec 28 '22 05:12

John H