Use properties of different models in view (.net MVC) - asp.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>

Related

How to implement image dynamically in multiple views?

I am looking for a way to display the Image dynamically based on Placement_Position and Region into different View.
Placement view, where I display all the content from table.
There is no link between these Views.
I am confused, how to implement this scenario. Anyone please help me here.
In Employee view, I want to display the image Atop_1if the region is 1 and Atop_2 if the region is 2
public class ClsPlacement
{
public int Id { get; set; }
public string Placement_Position { get; set; }
public string Path { get; set; }
public int Region { get; set; }
}
Controller
public ActionResult Placement()
{
var model = context.Placement.ToList();
return View(model);
}
Placement View
<table>
<tr>
<th>
#Html.DisplayNameFor(m => m.Id)
</th>
<th>
#Html.DisplayNameFor(m => m.Placement_Position)
</th>
<th>
#Html.DisplayNameFor(m => m.Region)
</th>
<th>
#Html.DisplayNameFor(m => m.Path)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
#Html.DisplayFor(modelItem => item.Id)
<td>
#Html.DisplayFor(modelItem => item.Placement_Position)
</td>
<td>
#Html.DisplayFor(modelItem => item.Region)
</td>
<td>
#Html.Image(item.Path, "Image")
</td>
</tr>
}
</table>
you can use LINQ to write query for each controller and return IList :
so in Employee view :
public ActionResult Employee()
{
IList<ClsPlacement> plcList = new List<ClsPlacement>();
var query= from m in context.Placement
select m;
var plc= query.ToList();
foreach(var plcData in plc)
{
if(plcData.Placement_Position=="A_Top")
{
plcList.Add(new ClsPlacement()
{
Id= plcData.Id,
Placement_Position= plcData.Placement_Position,
Path = plcData.Path ,
Region= plcData.Region
});
}
}
return View(plcList);
}
then in your view you can write this:
#foreach (var item in Model)
{
<div class="col-md-5">
<img src="#Url.Content(String.Format("~/Content/Place/{0}{1}{2}", "Atop_",item.Region,".jpg"))" />
</div>
}
and same this for Customer view.

lambda expression Problems

My question is when I click actionlink,the view send specific ID to controller(ex. ProductID = 6), but my controller grab all data to me not specific ID data.
I think the problem is the lambda expression at controller, it will grab all data to me.
These are my Models:
public class ShoppingCart
{
public List<ShoppingCartItemModel> items = new List<ShoppingCartItemModel>();
public IEnumerable<ShoppingCartItemModel> Items
{
get { return items; }
}
}
public class ShoppingCartItemModel
{
public Product Product
{
get;
set;
}
public int Quantity { get; set; }
}
Controller :
[HttpGet]
public ActionResult EditFromCart(int ProductID)
{
ShoppingCart cart = GetCart();
cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
});
return View(cart);
//return RedirectToAction("Index", "ShoppingCart");
}
private ShoppingCart GetCart()
{
ShoppingCart cart = (ShoppingCart)Session["Cart"];
//如果現有購物車中已經沒有任何內容
if (cart == null)
{
//產生新購物車物件
cart = new ShoppingCart();
//用session保存此購物車物件
Session["Cart"] = cart;
}
//如果現有購物車中已經有內容,就傳回 view 顯示
return cart;
}
View
#model ShoppingCart
#{
ViewBag.Title = "購物車內容";
}
<h2>Index</h2>
<table class="table">
<thead>
<tr>
<th>
Quantity
</th>
<th>
Item
</th>
<th class="text-right">
Price
</th>
<th class="text-right">
Subtotal
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.items)
{
<tr>
<td class="text-center">
#item.Quantity
</td>
<td class="text-center">
#item.Product.ProductName
</td>
<td class="text-center">
#item.Product.Price.ToString("c")
</td>
<td class="text-center">
#( (item.Quantity * item.Product.Price).ToString("c"))
</td>
<td>
#using (Html.BeginForm("RemoveFromCart", "ShoppingCart"))
{
#Html.Hidden("ProductId", item.Product.ProductID)
#*#Html.HiddenFor(x => x.ReturnUrl)*#
<input class="btn btn-warning" type="submit" value="Remove">
}
</td>
<td>
#using (Html.BeginForm("EditFromCart", "ShoppingCart", FormMethod.Get))
{
#Html.Hidden("ProductId", item.Product.ProductID)
<input class="btn btn-warning" type="submit" value="Edit">
}
</td>
</tr>
}
</tbody>
</table>
The key issue is that this code doesn't return the result of the LINQ queries, because you have not assigned a variable to the result:
cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
});
I strongly suggest you create a viewmodel specifically to display the cart items.
public class CartItemsViewModel
{
public List<ShoppingCartItemModel> Items { get; set; }
}
[HttpGet]
public ActionResult EditFromCart(int ProductID)
{
ShoppingCart cart = GetCart();
var viewModel = new CartItemsViewModel();
viewModel.Items.AddRange(cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
}));
return View(viewModel);
}
In my example I use the .AddRange() method to take the results of the LINQ calls against the cart items and store them in the viewmodel's Items property.
You must have to assign filtered value to cart like this.
cart.item = cart.items.Where(r => r.Product.ProductID == ProductID)
.Select(r => new ShoppingCartItemModel
{
Product = r.Product,
Quantity = r.Quantity
}).ToList();
use ToList(); or FirstOrDefault() as per your condition
You need to hold the return value from the linq query on cart.Items in a variable and pass that to the View method.
At the moment, the result of your query is being lost and the whole cart passed to the View method.

how to get selected checkbox in asp.net using entity framework

i'm new to asp.net mvc.I have a list of checkboxes and i want when the checkboxes are selected a new list of selected checkboxs are shown.
my code Product.cs code:
public class Product
{
public int ProductID { get; set; }
public string ProductName { get; set; }
public int Price { get; set; }
public bool Checked { get; set; }
public virtual ICollection<Purchase> Purchases { get; set; }
}
My view:
<h2>Product Lists</h2>
#using (Html.BeginForm())
{
<table class="table">
<tr>
<th>
Product ID
</th>
<th>
Product Name
</th>
<th>
Price
</th>
<th></th>
</tr>
#for (var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(x => x[i].ProductID)
</td>
<td>
#Html.DisplayFor(x => x[i].ProductName)
</td>
<td>
#Html.DisplayFor(x => x[i].Price)
</td>
<td>
#Html.CheckBoxFor(x => x[i].Checked, new { Style = "vertical-align:3px}" })
</td>
</tr>
}
</table>
<input type="submit" value="Purchase" class="btn btn-default" />
}
This is my Controller code.I want when the check boxes are selected in a new page the selected check boxes are shown.
my ActionResult:
public ActionResult Index()
{
return View(db.Products.ToList());
}
[HttpPost]
public ActionResult Index(List<Product> list)
{
return View(list);
}
#using (Html.BeginForm())
{
<table class="table">
<tr>
<th>
Product ID
</th>
<th>
Product Name
</th>
<th>
Price
</th>
<th></th>
</tr>
#for (var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(x => x[i].ProductID)
</td>
<td>
#Html.DisplayFor(x => x[i].ProductName)
</td>
<td>
#Html.DisplayFor(x => x[i].Price)
</td>
<td>
#Html.CheckBoxFor(x => x[i].Checked, new { Style = "vertical-align:3px}" })
</td>
</tr>
}
</table>
If you already have a List with all checked/unchecked properties and just want to show the checked records in a new view, you can store your list in a TempData and redirect to an action which will use your list:
public ActionResult Index()
{
return View(db.Products.ToList());
}
[HttpPost]
public ActionResult Index(List<Product> list)
{
TempData["CheckedRecords"] = list.Where(x=>x.Checked).ToList(); //Don't forget to add 'using System.Linq;'!
return RedirectToAction("MyOtherView");
}
public ActionResult MyOtherView()
{
var checkedRecords = (List<Product>)TempData["CheckedRecords"];
return View(checkedRecords);
}

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>

Error on listing the elements

I am getting the following error
The model item passed into the dictionary is of type 'System.Collections.Generic.List1[<>f__AnonymousType34[System.String,System.Int32,System.Int32,System.DateTime]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[ControllerName]'.
I did the code migration (database update) after that I want to just list the items by column name My code is as follows
public ActionResult Index()
{
DB db = new DB();
var categorylist = from a in db.categories
select new
{
a.CategoryName,
a.ID,
a.stock,
a.EntryDate
};
return View(categorylist.ToList());
}
Any help would be appreciated
Thanks in advance.
View is as follows
#model IEnumerable<Categories.Models.Categories>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create") </p> <table class="table">
<tr>
<th>#Html.DisplayNameFor(model => model.CategoryName)</th>
<th>#Html.DisplayNameFor(model => model.stock)</th>
<th>#Html.DisplayNameFor(model => model.EntryDate)</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>#Html.DisplayFor(modelItem => item.CategoryName)</td>
<td>#Html.DisplayFor(modelItem => item.stock)</td>
<td>#Html.DisplayFor(modelItem => item.EntryDate)</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
#Html.ActionLink("Details", "Details", new { id=item.ID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.ID })
</td>
</tr>
}
</table>
To take advantage of the model binding features of MVC you should create a view model which represents those the properties you want to display and/or edit (adjust property types as required)
public class CategoryVM
{
public int ID { get; set; }
public string CategoryName { get; set; }
public int Stock { get; set; }
public DateTime EntryDate { get; set; }
}
and change you method to
public ActionResult Index()
{
DB db = new DB();
var categorylist = (from a in db.categories
select new CategoryVM
{
CategoryName = a.CategoryName,
ID = a.ID,
Stock = a.stock,
EntryDate = a.EntryDate
}).ToList();
return View(categorylist);
}
View
#model List<CategoryVM>
<table>
<thead>
<tr>
<th>Category Name</th>
<th>stock</th>
<th>Entry Date</th>
...
</tr>
</thead>
<tbody>
#foreach(var item in Model)
{
<tr>
<td>#Html.DisplayFor(m => item.ID)<td>
<td>#Html.DisplayFor(m => item.CategoryName)</td>
...
</tr>
}
</tbody>
</table>
I think you need to Change the model type thar you defined in your view
Edit: Try
#model IList<dynamic>

Resources