Sending piece of model data back to controller as variable - asp.net-mvc

I have a view which imports data from a model and I need to make action links that send back a piece of the model data back to the controller
Index.cshtml
#model IEnumerable<App.Models.User>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Number)
</th>
<th>
#Html.ActionLink("Request", "Index", new { userNumber = //model.Number value })
</th>
</tr>
</table>
I have tried:
new { userNumber = model.Number }) //The name model does not exist in the current context
new { userNumber = Model.Number }) //IEnumerable does not contain a definition for ModelNumber (even though it does)

Since you are using a collection of users as your model, you need to iterate over your model with a foreach loop to get the values present on App.Models.User. The Number property would presumably be on your App.Models.User class, not on IEnumerable<App.Models.User>.
Something like this would work:
#foreach(App.Models.User user in Model) {
Html.ActionLink("Request", "Index", new { userNumber = user.Number })
}

Under your Views\Shared folder, add a DisplayTemplates folder.
Inside that folder, create a view called User.cshtml.
Add this:
<tr>
<th>
#Html.DisplayNameFor(model => model.Number)
</th>
<th>
#Html.ActionLink("Request", "Index", new { userNumber = model.Number })
</th>
</tr>
Then in your view, add this:
<table>
#Html.DisplayFor(model => model)
</table>

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

Bind viewmodel to partial view

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)

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>

How to remain/retain on the same page when using PagedList.mvc

I am using PagedList.Mvc and I have added a nice way to navigate across various pages in a mvc web application. However, when I click on an "edit" or "details" tab and save changes I am sent back to the 1st page. I want to remain on the same page where the changes were made.
Here is the code I have in the controller:
// GET: Item
public ActionResult Index(int? page)
{
var items = db.Items.Include(i => i.PurchaseOrder);
return View(items.ToList().ToPagedList(page ?? 1, 3));
}
Here is the code I have in the view:
#using PagedList;
#using PagedList.Mvc;
#model IPagedList<PurchaseOrders.Models.Item>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.First().ItemDescription)
</th>
<th>
#Html.DisplayNameFor(model => model.First().Quantity)
</th>
<th>
#Html.DisplayNameFor(model => model.First().Price)
</th>
<th>
#Html.DisplayNameFor(model => model.First().DueDate)
</th>
<th>
#Html.DisplayNameFor(model => model.First().DateReceived)
</th>
<th>
#Html.DisplayNameFor(model => model.First().Comments)
</th>
<th>
#Html.DisplayNameFor(model => model.First().PurchaseOrder.PurchaseRequest_)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ItemDescription)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.DueDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.DateReceived)
</td>
<td>
#Html.DisplayFor(modelItem => item.Comments)
</td>
<td>
#Html.DisplayFor(modelItem => item.PurchaseOrder.PurchaseRequest_)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ItemId }) |
#Html.ActionLink("Details", "Details", new { id=item.ItemId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ItemId })
</td>
</tr>
}
</table>
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
Please help!
You could pass an additional 'page` parameter to your edit method, for example
In your Index method, add
ViewBag.CurrentPage = page; // or use a view model property
Then your link would be
#Html.ActionLink("Edit", "Edit", new { id=item.ItemId, page = ViewBag.CurrentPage})
Then your edit method
[HttpGet]
public ActionResult Edit(int ID, int page)
{
ViewBag.CurrentPage = page; // pass current page to edit view
And your edit view
#using (Html.BeginForm(new { page = ViewBag.CurrentPage })) {
And in you post method
[HttpGet]
public ActionResult Edit(EditModel model, int page)
{
.... // Save
return RedirectToAction("Index", new { page = page });
In this case the page is stored in the ViewBag which makes it ephemeral (the ViewBag is only available for the current request).
In the controller, you're telling it if you get null use 1 as your current page. so null is always retuned and you get the 1st page everytime.
You need to provide the current page Number to your views that you navigate to (Edit/Create) and then provide it back to the original page when you're done.
You can use the TempData,that works well on HTTP redirects and lives longer than viewbag or viewData.
You can also move it arround with your models when calling actions and then give it back to the index action that needs a page number.
You can use sessions too. BTW, TempData is using session behind the scenes.
UPDATED:
Code to add in your index action:
var page = TempData["page"];
Code to add in the Create or Edit Submit action
//Get the page number
var page = TempData["page"];
//Set it back to Tempdata (because Tempdata is only for redirects) otherwise it will be lost
TempData["page"]=page;
add the value of the parameter to TempData["page"] when calling back the index action again
You can also access it from Index action directly since we repopulated it:
var page = TempData["page"];
return View(items.ToList().ToPagedList(page ?? 1, 3));
I also had this problem.
I tried to put it in the URL at first but it seems a bit weird to have ?page=2 in our URL.
So I replaced it with using TempData
What you need to do is this:
Store the page in TempData when you are in your Index() action method;
public const string PAGE_QUERY_STRING_KEY = "page";
public ActionResult Index(int page = 1)
{
TempData[PAGE_QUERY_STRING_KEY] = page;
...
}
Then use TempData.Peek(), instead of TempData[], everywhere else (to retain the value of your page between requests which are related to your current Index page) --- in your Edit, Create, Details, etc. action methods:
public ActionResult Edit(...)
{
...
return RedirectToAction(nameof(Index), new { page = TempData.Peek(PAGE_QUERY_STRING_KEY) });
// do not do this because this will remove the temp data
// return RedirectToAction(nameof(Index), new { page = TempData[PAGE_QUERY_STRING_KEY])
}
... and in your views:
<!--(Edit.cshtml)-->
...
<p>
#Html.ActionLink("Back to List", "Index",
new { page = TempData.Peek(FLP.Web.Controllers.UsersAdminController.PAGE_QUERY_STRING_KEY) })
</p>

EditorForModel() not working

I am using EditorForModel() to populate Data
Index Method :
public ActionResult Index()
{
SampleDbContext db = new SampleDbContext();
return View(db.Employees.ToList());
}
Index View :
#model IEnumerable<MultipleRowsDemo.Models.Employee>
<div style="font-family:Aria">
#using (Html.BeginForm())
{
<table border="1">
<thead>
<tr>
<th>
Select
</th>
<th>
Name
</th>
<th>
Email
</th>
</tr>
</thead>
<tbody>
#Html.EditorForModel()
</tbody>
</table>
}
</div>
but it is not working. It displays data like
123 Select Name Email
I read similar posts
EditorForModel and DisplayForModel do not work then passing class model within class model
It is suggested not use complex properties. I don't have one.
Another one is.
Displaying entities data with EditorForModel
It suggested to use
#using(Html.BeginForm())
{
...
}
I already have this.
Your Class Entity Name should match with the Name of the Template
Eg: If your ADO.net Employee entity name is "Employee" then the name of the template should be "Employee.cshtml" in Shared folder under Views directory

Resources