Bind viewmodel to partial view - asp.net-mvc

I have a model, which can represent 3 categories. I want in my view, make 3 different tables for each category with relevant fields. I think for this I need to use partial view with viewmodel for each category.
So my main model is "Ad", which have 3 sub viewmodels (Realty, Auto and Service).
Here the example how I implement Realty action on my home controller:
public ActionResult Realty()
{
var ads = db.Ads.Include(a => a.Realty);
var vm = new List<RealtyViewModel>();
foreach (var ad in ads)
{
vm.Add(new RealtyViewModel
{
Title = ad.Title,
Descirpiton = ad.Descirpiton,
Type = ad.Realty.Type,
NumberOfRooms = ad.Realty.NumberOfRooms
});
}
return PartialView(vm);
}
Then my partial view, looks like this:
#model IEnumerable<OGAS.Areas.Category.ViewModels.RealtyViewModel>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Type)
</th>
<th>
#Html.DisplayNameFor(model => model.Descirpiton)
</th>
<th>
#Html.DisplayNameFor(model => model.NumberOfRooms)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Type)
</td>
<td>
#Html.DisplayFor(modelItem => item.Descirpiton)
</td>
<td>
#Html.DisplayFor(modelItem => item.NumberOfRooms)
</td>
</tr>
}
</table>
Then in my Index page (without using any models), I call partial view like this:
#{Html.RenderPartial("Realty");}
But then I'm getting following error:
An exception of type 'System.NullReferenceException' occurred in App_Web_gdyh352c.dll but was not handled in user code
Could you please advise if this approach is good (calling 3 vms), if yes how to implement this?
Thanks.

Try to replace #{Html.RenderPartial("Realty");} and use #Html.Action("Realty") in this case, as you need to call back to the controller action, in order to create the model for the partial view.
See MVC Html.Partial or Html.Action for more information.

Use this, for .net core and mvc. #Html.Action has been removed from .net core
#await Html.PartialAsync("_YourPartialViewName", YourModel)

Related

mvc-Passing query data from controller to view

i want to show my data from DB with query.
now i see the data but it show all table (dog) and i dont
successful combain query.
i want add query for display the dog_num from the smallest to grow
select * from dog order By dog_num desc
my code:
view
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.dog_num)
</th>
<th>
#Html.DisplayNameFor(model => model.dog_name)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.dog_num)
</td>
<td>
#Html.DisplayFor(modelItem => item.dog_name)
</td>
</tr>
controller
private model db = new model();
public ActionResult Index()
{
return View(db.dog.ToList());
}
alex, this is very simple
You need to choose a Property to sort by and pass it as a lambda expression to OrderByDescending
like:
.OrderByDescending(x => x.dog_num);
Example:
your Tsql:
select * from dog order By dog_num desc
Equivalent linq:
db.dog.ToList().OrderByDescending(x => x.dog_num);
Final controller code:
private model db = new model();
public ActionResult Index()
{
return View(db.dog.ToList().OrderByDescending(x => x.dog_num));
}
Hope this is what you want ,kindly let me know your thoughts or feedbacks
Thanks
karthik

Use single IEnumerable value before For Each

I have a view that lists auditorium names of a theater.
#ModelType IEnumerable(Of dbtheatersinfo.TheaterAuditorium)
<h2>Theater Auditoriums</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(Function(model) model.Theater.TheaterName)
</th>
<th>
#Html.DisplayNameFor(Function(model) model.TheaterAuditoriumName)
</th>
</tr>
#For Each item In Model
#<tr>
<td>
#Html.DisplayFor(Function(modelItem) item.Theater.TheaterName)
</td>
<td>
#Html.DisplayFor(Function(modelItem) item.TheaterAuditoriumName)
</td>
</tr>
Next
</table>
All auditoriums listed here have the same TheaterName, so I would like to display the first instance of TheaterName in the tag (and remove it from the list). I tried:
<h2>Auditoriums for #Html.DisplayFor(Function(model) model.Theater.TheaterName) </h2>
But that gives me, "'Theater' is not a member of 'IEnumerable(of TheaterAuditorium)'." The data is in there; it's displaying within the For Each loop. I just can't figure out how to use it before the loop.
I asked the wrong question, but ended up needing the answer anyway. To do this View properly, I needed a View Model:
Namespace ViewModels
Public Class AuditoriumIndex
Public Property TheaterAuditorium As IEnumerable(Of TheaterAuditorium)
Public Property Theater As Theater
End Class
End Namespace
In the controller:
Dim viewModel = New AuditoriumIndex()
viewModel.TheaterAuditorium = db.TheaterAuditoriums.Where(Function(a) a.TheaterID = id).SortBy("TheaterAuditoriumName")
viewModel.Theater = db.Theaters.Where(Function(a) a.TheaterID = id).SingleOrDefault()
Return View(viewModel)
And the View:
h2>Auditoriums for #Html.DisplayFor(Function(model) model.Theater.TheaterName)</h2>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(Function(model) model.TheaterAuditorium.FirstOrDefault().TheaterAuditoriumName)
</th>
</tr>
#For Each item In Model.TheaterAuditorium
#<tr>
<td>
#Html.DisplayFor(Function(modelItem) item.TheaterAuditoriumName)
</td>
</tr>
Next
</table>
Here I had to use FirstOrDefault() to access the column name outside of the loop.

MVC Object(x) does not contain a definition for blah

Getting an error on the view, at the displaynamefor softwareid line, saying the model SoftwareDTO does not contain a definition for softwareid. I can see it right there in the model.
Model:
public class SoftwareDTO
{
public int SoftwareId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
Controller:
public ActionResult Index()
{
List<SoftwareDTO> softwareList = new List<SoftwareDTO>();
var data = _db.Software.ToList();
foreach (var sw in data)
{
SoftwareDTO software = new SoftwareDTO()
{
SoftwareId = sw.SoftwareId,
Name = sw.Name,
Description = sw.Description
};
softwareList.Add(software);
};
return View(softwareList);
}
View:
#model List<Request.Models.SoftwareDTO>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.SoftwareId)
</th>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.SoftwareId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
its because model its a list not an object SoftwareDTO in your razor view
I think you are missing the foreach
SoftwareId is a property of SoftwareDTO class. Your view is strongly typed to a collection of SoftwareDTO objects. So you need to loop through the model(The collection of SoftwareDTO) and access the SoftwareId of each item.
#model List<Request.Models.SoftwareDTO>
<table class="table">
#foreach(var item in Model)
{
<tr>
<td>
#Html.DisplayNameFor(x=> item.SoftwareId)
</td>
</tr>
}
</table>
EDIT : As per the edit in the question, and the comments provided.
Looks like you want to print the display name of the propertes in your table headers. If you do not wish to change the data you are passing from your action method, you can try this
#if (Model.Any())
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(x => Model[0].SoftwareId)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(x => item.SoftwareId)
</td>
</tr>
}
</table>
}
This is using the first item in the collection and it's properties to use with DisplayNameFor method. Since i have a if condition to check for at least one item before rendering the table, It will not even render the table if your Model has 0 items.
If you want to show the empty table with headers, you have 2 options.
Write HTML markup for the table header
<table class="table">
<tr>
<th>
<label>Software Id</label>
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(x => item.SoftwareId)
</td>
</tr>
}
</table>
Or if you still want to use the DisplayNameFor helper method to render the table header labels,
Create a new viewmodel
public class TableListVm
{
public List<SoftwareDTO> Items {set;get;}
public SoftwareDto ItemMeta {set;get;}
public TableListVm()
{
ItemMeta= new SoftwareDto();
}
}
And in your GET action, Send this object to your view
public ActionResult Index()
{
var data = _db.Software.ToList().Select(sw=> new SoftwareDTO {
SoftwareId = sw.SoftwareId,
Name = sw.Name,
Description = sw.Description
}).ToList();
var vm= new TableListVm { Items = data };
return View(vm);
}
And in your view which is strongly typed to this new view model.
#model TableListVm
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(x => Model.ItemMeta.SoftwareId)
</th>
</tr>
#foreach (var item in Model.Items)
{
<tr>
<td>
#Html.DisplayFor(x => item.SoftwareId)
</td>
</tr>
}
</table>

C# MVC4 Partial View with other ActionResult in Controller

i have a problem.
I have my Controller "DashboardNB2Controller", my View "index.cshtml" and i want to integrate a partial view called "_PartialView.cshtml" in my "index.cshtml". Both Views are in the same folder. In my controller, i have the "ActionResult _PartialView" for a databaseoperation in my partial view.
But if I integrate my partial view in my index view, the action result "_PartialView" didn't work. I get no results. The query for my database is correct. I checked this.
Here are my codes
My Controller with the ActionResult for the Partial View
public ActionResult _PartialView()
{
var lastMessages= (from t in db.view_tbl_message
orderby t.Date descending
select t).Take(10);
ViewModelDashboard model = new ViewModelDashboard();
model.view_tbl_message = lastMessages.ToList();
return PartialView("_PartialView", model);
}
My index.cshtml
#model AisWebController.Areas.Statistics.Models.ViewModelDashboard
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br />
#{Html.Action("_PartialView", "DashboardNB2");}
<br />
And my _PartialView.cshtml
#model WebApplication.Areas.Stats.Models.ViewModelDashboard
<table class="table table-bordered">
<tr>
<th>
Date
</th>
<th>
User
</th>
<th>
Message
</th>
</tr>
#foreach (var item in Model.view_tbl_message)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date
</td>
<td>
#Html.DisplayFor(modelItem => item.User)
</td>
<td>
#Html.DisplayFor(modelItem => item.Message)
</td>
</tr>
}
</table>
If someone can help - that would be aweseome!
Change
#{Html.Action("_PartialView", "DashboardNB2");}
to
#Html.Action("_PartialView", "DashboardNB2")
You don't need {} brackets after you have # in view for Html extension methods
Look your #Html.DisplayFor it doesn't have any {} brackets.
Same applies for #Html.ActionLink

MVC update list items

Hi I have a view which displays Invoices and InvoiceLines.
#model VectorCheck.ViewModels.InvoiceViewModel
#{
ViewBag.Title = "Invoice Details";
}
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.11.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/EditorHookup.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<fieldset>
<legend>Invoice</legend>
<table>
<tr>
<th>
Activity ID
</th>
<th>
Invoice Line Amount
</th>
<th>
Payment Type
</th>
<th>
Note
</th>
<th>
</th>
<th>
</th>
<th>
</th>
</tr>
#foreach (var item in Model.InvoiceLines) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Activity.Descriptor)
</td>
<td>
#Html.DisplayFor(modelItem => item.Amount)
</td>
<td>
#Html.DisplayFor(modelItem => item.PaymentType.Name)
</td>
<td>
<span>Person:</span>
#Html.DropDownListFor(modelItem => item.PersonrId, Model.People as IDictionary<string, IEnumerable<SelectListItem>>, "--- Select ---")
</td>
<td>
<input type="submit" value="Update" />
</td>
</tr>
}
}
</table>
</fieldset>
}
What I'm wanting is for each InvoiceLine without going to another screen to be able to change the value in the dropdown list for Person, click update and get this updated InvoiceLine in the controller where I can save it.
However when I get to the controller the InvoiceLine does not contain the values.
Controller method:
[HttpPost]
public ActionResult EditInvoiceLine(InvoiceLine invoiceLine, int id)
{
return View(invoiceLine);
}
Has anyone achieve anything like this on the same page or knows how to do it?
No, I do not want to use jqgrid. I have other functionality which jqgrid isn't suitable for.
InvoiceLine is empty because the controller doesn't know where it's coming from. Also, where is the 'id' coming from? Shouldn't it be 'Personid'? Easiest technique in my opinion would be just to use ajax on the button click and send values using GET through querystrings.
I would use a form per line approach (with or without AJAX). Note this will be easier if you use a non-table-based layout. At a minimum, your submit button will need to share the same table element with the input that you want to post back. Further, you could probably get by with just the line id and the person id, instead of the whole model. Use the line id to fetch the entity from the db, then update the person id and save it. Remove the surrounding form and put a form inside each table element with the dropdown list (moving the submit button as well). Modify the signature of your action to match.
#foreach (var item in Model.InvoiceLines) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Activity.Descriptor)
</td>
<td>
#Html.DisplayFor(modelItem => item.Amount)
</td>
<td>
#Html.DisplayFor(modelItem => item.PaymentType.Name)
</td>
<td>
#using (Html.BeginForm("EditInvoiceLine", new { id => modelItem.InvoiceId } ))
{
<span>Person:</span>
#Html.DropDownListFor(modelItem => item.PersonrId, Model.People as IDictionary<string, IEnumerable<SelectListItem>>, "--- Select ---")
<input type="submit" value="Update" />
}
</td>
</tr>
}
[HttpPost]
public ActionResult EditInvoiceLine( int id, int personId )
{
var line = db.InvoiceLines.SingleOrDefault( id );
line.PersonId = personId;
db.SaveChanges();
return View( line ); // more more likely a model based on the line...
}

Resources