How to set a Viewmodel from several Models? - asp.net-mvc

I would like to retrieve several items in one cell of a table in my view. I have several models, Product, Pack(as category), Order and OrderDetail. I think to achieve what I want, I should create a view model with data from my Models, but I don't really know how to do this and wich data i should bind.
This my view
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.OrderId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.ClientID)
</td>
<td>
#Html.DisplayFor(modelItem => item.SiteNumber)
</td>
<td>
#if (item.Pack == null)
{
<ul>
#foreach (var tmp in item.????) //PRODUCT
{
<li>Html.DisplayFor(modelItem => tmp.Name) </li>
}
</ul>
}
else
{
<ul>
#foreach (var tmp in item.????) //PACK
{
<li>Html.DisplayFor(modelItem => tmp.Name) </li>
}
</ul>
}
</td>
<td>
#{
if (item.Pack == null)
{
<ul>
#foreach (var tmp in item.????) // PRODUCT
{
<li>Html.DisplayFor(modelItem => tmp.UnitPrice)
</li>
}
</ul>
}
else
{
<ul>
#foreach (var tmp in item.????) //PACK
{
<li>
#Html.DisplayFor(modelItem => tmp.UnitPricePack)
</li>
}
</ul>
}
}
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.Total)
</td>
<td>
#Html.DisplayFor(modelItem => item.OrderDate)
</td>
</tr>
I would like my table looks like that at the end :
My question again, How can I create a ViewModel to retrieves data in my view and for it match with my #foreach condition inside ma table... I don't know if I am clear enough... This post follow this one . Actually, what i've done returns me error on error, I don't really know how to set up my viewmodel, which data I need to bind and how. Thanks for your help, your advices, I take all

You don't necessarily need a new ViewModel, Order has all you need. Your model will be a list of orders.
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.OrderId)
</td>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.ClientID)
</td>
<td>
#Html.DisplayFor(modelItem => item.SiteNumber)
</td>
<td>
<ul>
#foreach (var o in item.OrderDetails)
{
if (o.Pack == null)
{
<li>#Html.DisplayFor(modelItem => o.Product.Name) </li> //PRODUCT
}
else
{
<li>#Html.DisplayFor(modelItem => o.Pack.Name) </li> // PACK
}
}
</ul>
</td>
<td>
<ul>
#foreach (var o in item.OrderDetails)
{
if (o.Pack == null)
{
<li>#Html.DisplayFor(modelItem => o.UnitPrice) </li> //PRODUCT
}
else
{
<li>#Html.DisplayFor(modelItem => o.UnitPricePack) </li> //PACK
}
}
</ul>
</td>
<td>
<ul>
#foreach (var o in item.OrderDetails)
{
<li>#Html.DisplayFor(modelItem => o.Quantity)</li>
}
</ul>
</td>
<td>
#Html.DisplayFor(modelItem => item.Total)
</td>
<td>
#Html.DisplayFor(modelItem => item.OrderDate)
</td>
</tr>
}
Update according to your update:
You are still trying to pass collection of orderdetails instead of orders
instead of this:
var user = from m in db.OrderDetails
select m;
Have this ( assuming you have Orders table):
public ActionResult Index(string searchSite, string searchString)
{
var user = from m in db.Orders
select m;
if (!String.IsNullOrEmpty(searchString))
{
user = user.Where(s => s.ClientID.Contains(searchString));
}
if (!String.IsNullOrEmpty(searchSite))
{
user = user.Where(c => c.SiteNumber.Contains(searchSite));
}
return View(user);
}

i would suggest use of `AutoMapper', you can try
public class A{
public string FirstName{get;set;}
}
public class B{
public string LastName{get;set;}
}
now create a view mode
public class VModel{
public string FirstName{get;set;}
public string LastName{get;set;}
}
and where you want them to converge use auto mapper like
Mapper.CreateMap<A,VModel>();
Mapper.CreateMap<B,VModel>();
var ObjectOfClassA= new A{FirstName="John"};
var ObjectOfClassB= new A{LastName="Smith"};
VModel _model = Mapper.Map<A,VModel>(ObjectOfClassA);
_model = Mapper.Map<B,VModel>(ObjectOfClassB);
access it like
_model.FirstName;//should give you john
_model.LastName;//should give you smith

Related

Nested foreach loop in ASP.NET MVC

I have problem with my nested foreach. As you see in the screenshot, it just returns all data in every dt.
I know how to solve my problem with a partial view. But I just want to know is there solution with foreach or some other loop.
public class VM
{
public IEnumerable<x> Upi { get; set; }
public IEnumerable<y> Adre { get; set; }
}
View
#foreach (var item in Model.Upi)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Surname)
</td>
<td>
#foreach (var smece in Model.Adre)
{
<div>
<pre>
#Html.DisplayFor(modelItem => smece.Ul)
#Html.DisplayFor(modelItem => smece.Ku), #Html.DisplayFor(modelItem => smece.Gr)
</pre>
</div>
}
</td>
Sorry guys I am stupid. It was simple. I just had to put one if.
if (smece.AU_ID == item.AU_ID) before pre and it works. TY all. Now only problem is, is there maybe other way where it doesnt need to iterate whole foreach and just go to direct AU_ID.

How to call multiple partials in parent view in MVC4?

I am trying to call multiple partials in parent view. I have tried multiple way but could not succeed. I think there is something missing in View. Please guide me where i am going wrong.
Note: I have partials in the question. Please suggest me.
The following error:
System.InvalidOperationException: 'The model item passed into the
dictionary is of type 'Aplication.Models.ABC.ClsA', but this
dictionary requires a model item of type
'System.Collections.Generic.IEnumerable`1[Aplication.Models.ABC.first]'.'
Model
public class ClsA
{
public List<first> firsts{ get; set; }
public List<second> seconds{ get; set; }
}
public class first
{
public string Name { get; set; }
public string Address { get; set; }
}
public class second
{
public string Details{ get; set; }
public string Age{ get; set; }
}
Controller
public ActionResult ABC()
{
SDetails sDetails=new SDetails();
var model = new ClsA();
model.firsts = sDetails.Rst();
model.seconds = sDetails.Rs();
return View(model);
}
View
#model Aplication.Models.ABC.ClsA
#Html.Partial("_PartialA");
#Html.Partial("_PartialB.cshtml")
_PartialA
#model IEnumerable<Aplication.Models.ABC.first>
<table>
<tr>
<th>#Html.DisplayNameFor(m => m.Name)</th>
<th>#Html.DisplayNameFor(m => m.Address)</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Address)
</td>
</tr>
}
</table>
_PartialB
#model IEnumerable<Aplication.Models.ABC.second>
<table>
<tr>
<th>#Html.DisplayNameFor(m => m.Details)</th>
<th>#Html.DisplayNameFor(m => m.Age)</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Details)
</td>
<td>
#Html.DisplayFor(modelItem => item.Age)
</td>
</tr>
}
</table>
#Html.Partial() Takes a second parameter model. If you do not pass the parameter to #Html.Partial() it will automatically pass the model of the current view.
Parameters
htmlHelper
Type: System.Web.Mvc.HtmlHelper
The HTML helper instance that this method extends.
partialViewName
Type: System.String
The name of the partial view to render.
model
Type: System.Object
The model for the partial view.
You need to update your code from
#Html.Partial("_PartialA");
#Html.Partial("_PartialB");
To
#Html.Partial("_PartialA", Model.firsts);
#Html.Partial("_PartialB", Model.seconds)
You do not need to pass the file extension to the #Html.Partial method
This is an example of loading partial view. The controller has an action to load the data in a partial view.
public ActionResult List()
{
var movies = db.Movies;
return PartialView("_list", movies.ToList());
}
In the partial _list view, you can have something like -
#model IEnumerable<WebApplication1.Models.Movie>
<div class="row">
<table class="table table-bordered table-hover" id="moviesTable">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.ID)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.ReleaseDate)
</th>
<th>
#Html.DisplayNameFor(model => model.Genre)
</th>
<th>
#Html.DisplayNameFor(model => model.Price)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.ReleaseDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Genre)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<div class="btn-group btn-group-xs">
<i class="fa fa-trash-o"></i>
<i class="glyphicon glyphicon-pencil"></i> Edit
<i class="glyphicon glyphicon-eye-open"></i> View
<i class="glyphicon glyphicon-trash"></i> Delete
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
Now you can render the partial view in the main view like below -
<div class="row">
<div class="col-md-12" id="replacetarget">
#{ Html.RenderAction("List", "Movies"); }
</div>
</div>

Add Search Engine into MVC Music Store

i'm trying to add search the title plus genre drop down list inside store in mvc music store. here's the procedure i've done
firstly i'v added the below code into the StoreManagere controller
public ActionResult SearchIndex(string musicGenre, string searchString)
{
var GenreLST = new List<string>();
var GenreQry = from d in db.Genres
orderby d.Name
select d.Name;
GenreLST.AddRange(GenreQry.Distinct());
ViewBag.movieGenre = new SelectList(GenreLST);
var musics = from m in db.Albums.Include(a => a.Genre).Include(a => a.Artist)
select m;
if (!string.IsNullOrEmpty(searchString))
{
musics = musics.Where(s => s.Title.Contains(searchString));
}
if (string.IsNullOrEmpty(musicGenre))
return View(musics);
else
{
return View(musics.Where(x => x.Genre.Name == musicGenre));
}
}
and the below code inside search index view page
#model IEnumerable<MvcMusicStore.Models.Album>
#{
ViewBag.Title = "SearchIndex";
}
<h2>SearchIndex</h2>
<p>
#Html.ActionLink("Create New", "Create")
#using (Html.BeginForm()) {
<p>Genre : #Html.DropDownList("musicGenre", "All")
Title : #Html.TextBox("searchString")
<input type="submit" value="Filetr" /></p>
}
</p>
<table>
<tr>
<th>
Genre
</th>
<th>
Artist
</th>
<th>
Title
</th>
<th>
Price
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Genre.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Artist.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.AlbumId }) |
#Html.ActionLink("Details", "Details", new { id=item.AlbumId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.AlbumId })
</td>
</tr>
}
</table>
but i get this error
There is no ViewData item of type 'IEnumerable' that has the key 'musicGenre'.
You saved your genre list in ViewBag.movieGenre not musicGenre. That's why it is not working.

Passing entire Model from a View back to the Controller

I got a list of:
public class Items
{
public String Nro_Item { get; set; }
public Sucursal Sucursal { get; set; }
public Areas Area { get; set; }
public Sectores Sector { get; set; }
public bool ID_Estado { get; set; }
}
I'm passing it to this view:
#using ClientDependency.Core.Mvc
#model IEnumerable<TrackingOperaciones.Controllers.Items>
#{
ViewBag.Title = "Ver Items";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<br/>
#using (Html.BeginForm("CargarRecibidos", "Recepcion", FormMethod.Post))
{
<table class="table table-striped table-bordered table-condensed">
<tr>
<th>
Numero
</th>
<th>
Sucursal
</th>
<th>
Area
</th>
<th>
Sector
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Nro_Item)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sucursal.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Area.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sector.Descripcion)
</td>
<td>
#Html.CheckBoxFor(modelItem => item.ID_Estado)
</td>
</tr>
}
</table>
<p>
<input class="btn" name="Guardar" type="submit" value="Guardar"/> |
#Html.ActionLink("Volver al listado de RecepciĆ³n", "Index")
</p>
}
Until there everything is fine: Now the problem is getting back the entire model with the checked values in a controller for processing it like this one:
[HttpPost]
public ActionResult CargarRecibidos(IEnumerable<Items> items)
{
if (ModelState.IsValid)
{
//do something here
}
return RedirectToAction("Index");
}
}
But i'm falling miserably because "items" came back empty in the postback
i'm guess something is wrong with the form
#using (Html.BeginForm("CargarRecibidos", "Recepcion"))
{
<input class="btn" name="Guardar" type="submit" value="Guardar"/>
}
please help me!
Use IEnumerable
Then the controller input parameter will be List
Perhaps also consider using AJAX POST with JSON objects in place of a form submit (more modern/elegant) but submits are fine too.
Part of the problem is it won't post the entire model since only the checkbox is a form value. I think you need to add an additional hidden value in your form to track the item number and then handle the checkbox values specially in the controller. The item number is appended to "checkbox" in the posted values to keep them distinct.
<tr>
<td>
#Html.DisplayFor(modelItem => item.Nro_Item)
#Html.Hidden("Nro_Item", item.Nro_Item)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sucursal.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Area.descripcion)
</td>
<td>
#Html.DisplayFor(modelItem => item.Sector.Descripcion)
</td>
<td>
#Html.CheckBox("checkbox" + item.Nro_Item, item.ID_Estado)
</td>
</tr>
In the controller only bind to the number item so it can be used to process the checkboxes:
[HttpPost]
public ActionResult CargarRecibidos(List<string> nro_item)
{
foreach (string item in nro_item)
{
var checkbox=Request.Form["checkbox" + item];
if (checkbox != "false") // if not false then true,false is returned
{
// Do the action for true...
}
else
{
// Do the action for false
}
}
return View();
}

Use properties of different models in view (.net MVC)

I am learning MVC and display a list of products in a view.
#model IEnumerable<Domain.Model.Product>
<table>
<tr>
<th style="width:50px; text-align:left">Id</th>
<th style="text-align:left">Name</th>
<th style="text-align:left">Category</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Category.Name)
</td>
</tr>
}
</table>
The products belong to categories, which are displayed in the right column. I now want to filter the products by categories, for which I would like to use a dropdownlist control. I found #Html.DropDownListFor(), but as far as I understand, this will only give me properties of the currently underlying model (Product).
My controller:
public class ProductController : Controller
{
ProductRepository pr = new ProductRepository();
public ActionResult Default()
{
List<Product> products = pr.GetAll();
return View("List", products);
}
}
You could do something like this. Just create a class with the info that you need.
public class ProductsModel
{
public ProductsModel() {
products = new List<Product>();
categories = new List<SelectListItem>();
}
public List<Product> products { get;set; }
public List<SelectListItem> categories { get;set; }
public int CategoryID { get;set; }
}
Then your controller:
public class ProductController : Controller
{
ProductRepository pr = new ProductRepository();
public ActionResult Default()
{
ProductsModel model = new ProductsModel();
model.products = pr.getAll();
List<Category> categories = pr.getCategories();
model.categories = (from c in categories select new SelectListItem {
Text = c.Name,
Value = c.CategoryID
}).ToList();
return View("List", model);
}
}
Finally, your view
#model IEnumerable<Domain.Model.ProductsModel>
#Html.DropDownListFor(m => model.CategoryID, model.categories)
<table>
<tr>
<th style="width:50px; text-align:left">Id</th>
<th style="text-align:left">Name</th>
<th style="text-align:left">Category</th>
</tr>
#foreach (var item in Model.products) {
<tr>
<td>
#item.Id
</td>
<td>
#item.Name
</td>
<td>
#item.Category.Name
</td>
</tr>
}
</table>

Resources