I am having trouble understanding if this is possible or not. I have a stored procedures and a view model classes and one controller. Is it possible that I could add another view model class with a different stored procedure to use one controller and display the the information from both stored procedures into one view?
This is my current Model:
public class People
{
public class Jobs
{
public int jobID { get; set; }
public string jobName { get; set; }
}
public class Names
{
public int userId{get;set}
public string userName {get; set;}
}
}
In MVC we cannot pass multiple models from a controller to the single view.
Controller is the boss, so a Controller decides which View to be rendered and Views does not / cannot care which Controller requested the View. You can / will absolutely have multiple Views from a Controller.
You can use multiple models in a single view by creating a common model for all the models that are to be used in a single view. To achieve this, refer to the following steps. First, create a new model (common for all models) and refer all other models that are to be used in the same view.
Yes, you can use Tuple (brings magic in view having multiple model).
Yes, this is totally possible. Simply create a view model that contains the properties that would be populated by your stored procedures and then pass that to your view:
public class PeopleViewModel
{
public List<Job> Jobs { get; set; }
public List<Name> Names { get; set; }
}
Then the action method:
public ActionResult Index()
{
var model = new PeopleViewModel();
model.Jobs = // ... fetch from database
model.Names = // ... fetch from database
return View(model);
}
As you've stated Jobs
and Names
are collections, the model code you've shown won't solve your problem. It sounds like this is what you really want:
public class Job // Notice I've removed the pluralisation
{
public int jobID { get; set; }
public string jobName { get; set; }
}
public class Name // Notice I've removed the pluralisation
{
public int userId { get; set; }
public string userName { get; set; }
}
Now, your People
class can contain lists of those:
public class People
{
public List<Job> Jobs { get; set; }
public List<Name> Names { get; set; }
}
Now you can wrap this in a view model:
public class PeopleViewModel
{
public People People { get; set; }
}
Then you would populate it from your action:
public ActionResult Index()
{
var model = new PeopleViewModel();
model.People = // ... fetch from database
return View(model);
}
The thing is, if Jobs
and Names
are unrelated, there's no point in wrapping them in a People
class first. You'd simply do the following (as discussed above):
public class PeopleViewModel
{
public List<Job> Jobs { get; set; }
public List<Name> Names { get; set; }
}
Think of a view model as a way of representing just a slice of the data you want to display in your view, nothing more, nothing less. All the code above does is define what data you'd like to see in that view. As the properties on the view model are public, you can populate them in your controller's action using whatever method you currently use.
I think it would probably be helpful to show you a full example as to how fits together for your views. Firstly, I'll show you the quick and dirty way of accessing the data in your view model and then afterwards I'll show you how to do the same with DisplayTemplates
.
So first up, let's assume we have an action called Index
like the following:
public ActionResult Index()
{
var model = new PeopleViewModel();
model.Jobs = // ... fetch from database
model.Names = // ... fetch from database
return View(model);
}
Here's the Index
view:
@model PeopleViewModel
@foreach (var job in Model.Jobs)
{
@Html.DisplayFor(m => job.JobId)
@Html.DisplayFor(m => job.JobName)
}
@foreach (var name in Model.Names)
{
@Html.DisplayFor(m => name.UserId)
@Html.DisplayFor(m => name.UserName)
}
Notice how the view expects an instance of PeopleViewModel
and it's simply looping over each individual item in each collection, printing the contents. However, whilst this is fine for very simple views, mixing logic with your HTML becomes a maintenance headache with more complicated views and larger projects. With that in mind, we can make use of DisplayTemplates
instead.
The action in your controller remains the same. However, we need to make some other changes. What we're working towards is turning the Index
view into this:
@model PeopleViewModel
@Html.DisplayFor(m => m.Jobs)
@Html.DisplayFor(m => m.Names)
By calling Html.DisplayFor
in this way, it will try to locate a DisplayTemplate
which corresponds to the data type it's being passed. In this case, the helper is smart enough to know that we're passing collections to it and so it will look for a template that matches the data type the collection contains. That means we need to make templates for the types Job
and Name
. To do that, follow these steps:
DisplayTemplates
folder inside your view's current folder (e.g. if your view is Home\Index.cshtml
, create the folder Home\DisplayTemplates
).Job.cshtml
and Name.cshtml
, respectively).Now you can move all of the display logic into those two templates. So they would look like the following:
Job.cshtml
@model Job
@Html.DisplayFor(m => m.JobId)
@Html.DisplayFor(m => m.JobName)
Name.cshtml
@model Name
@Html.DisplayFor(m => m.UserId)
@Html.DisplayFor(m => m.UserName)
Hopefully that clears things up a little.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With