Search code examples
c#asp.netasp.net-mvcasp.net-mvc-viewmodel

How to create VIew of ViewModel, where ViewModel is an IEnumerable with two strings?


I have been working on an MVC ViewModel that contains scalar data values I need to pass to the View (instead of using ViewBags) along with an IEnumerable that contains the tabular data that goes in the table. This was based on a suggestion someone made on an earlier SO question. This way, there is no duplication I would have if I added the scalar values as constants to a table that could have many, many rows.

I am pasting my (simplified) data model and view model definitions and the controller action in question. The data structures are what I need it to be, but Visual Studio won't create a View from this Action (right-click and select "Add View with Model").

My question, is given the Action and Model definitions, what do I need to do so that I can create a View of the View Model?

I'm figuring auto-scaffold is out of the question because the ViewModel has no key, so I'm expecting manual coding. I have no idea how to do this, because all the examples I've seen show ViewModels that are essentially the equivalent of merging two tables into a larger table.

I have tried using @model = [ViewModelName] and @model = IEnumerable, but both failed.

The binary response would be, "Duh, the error is telling you exactly what's going on. You don't have a Key." But that response doesn't help me resolve this. How do I move forward with this definition of the ViewModel and create a View?

View Model

public class StudentRosterViewModel
{        
    // This list is the "table" shown on the view
    public IEnumerable<StudentRoster> StudentRosters { get; set; }

    // These are scalar values apply to the view as a whole
    public string SelectedCampus { get; set; }
    public string SelectedFiscalYear { get; set; }
}

Data Model

[Table("StudentRoster")]
public partial class StudentRoster
{
    public int ID { get; set; }

    [Required]
    [StringLength(3)]
    public string Campus { get; set; }

    [Required]
    [StringLength(4)]
    public string FiscalYear { get; set; }

    [Required]
    [StringLength(50)]        
    public string StudentName { get; set; }

    public int StudentID { get; set; }
}

Controller Action:

public ActionResult FilterableIndex(string campus="MRA",string fiscalYear = "FY16")
{       
    StudentRosterViewModel vm = new StudentRosterViewModel();

    // this is tabular data and goes in the "table"
    vm.StudentRosters = db.StudentRosters
        .Where(m => m.Campus == campus)
        .Where(m => m.FiscalYear == fiscalYear)
        .ToList();

    // These are scalar values; they are not tabular
    // These are needed to supply values to jQuery 
    vm.SelectedCampus = campus;
    vm.SelectedFiscalYear = fiscalYear;

    return View(vm);
}

Solution

  • The convention is that in your Views folder there's a folder corresponding to the name of your controller. For example, if the controller is StudentRosterController then the folder would be named StudentRoster.

    Then the view would correspond to the name of the action - FilterableIndex.cshtml.

    The .cshtml file would begin with

    @model MvcApp.Controllers.StudentRosterViewModel
    

    (Where MvcApp.Controllers is the namespace that contains your model.)