I have a list of categories and sub categories which is passing from controller to the view. Now, I want them to be represented in the HTML like following. But, I dont know how can i achieve this by using foreach or table or whatever.
EDIT : Code
public ActionResult Electronics()
{
var topCategories = pe.Categories.Where(category => category.ParentCategory.CategoryName == "Electronics").ToList();
//var catsAndSubs = pe.Categories.Include("ParentCategory").Where(c => c.ParentCategory.CategoryName == "Electronics");
return View(topCategories);
}
With this view code, I am just able to pull a vertical list.
#foreach (var cats in Model)
{
<li>#cats.CategoryName</li>
foreach (var subcats in cats.SubCategories)
{
<li>#subcats.CategoryName</li>
}
}
When designing HTML mark-up it is very important to consider semantics. What meaning are you trying to convey? That doesn't look like tabular data to me so please don't put it in tables :P
Based on your wireframe above, the way I would probably structure this is like this:
<h1>Category Directory</h1>
<h2>Multimedia Projectors</h2>
<h2>Home Audio</h2>
<p>
Amplifiers, Speakers
</p>
Adjust the hX tags to reflect their position within the document's hierachy. Remember to only ever have ONE h1 per page (or per <acticle>, or <section> if using HTML5).
If instead you wind up turning this into something like a Superfish menu then this is the markup that you would use:
<nav id="category_menu">
<ul>
<li>
Multimedia Projectors
</li>
<li>
Home Audio
<ul>
<li>
Amplifiers
</li>
<li>
Speakers
</li>
</ul>
</li>
</ul>
</nav>
Edit
Your model is not suitable for creating your desired view, the relationship is bottom-up, but to conveniently construct the view you will want the relationships defined top-down. You need to start by converting the data model into a view model, such as:
class CategoryViewModel
{
string CategoryName { get;set; }
IList<CategoryModel> SubCategories { get;set; }
}
and to make this:
IList<CategoryViewModel> Map(IList<CategoryDataModel> dataModel)
{
var model = new List<CategoryViewModel>();
//Select the categories with no parent (these are the root categories)
var rootDataCategories = dataModel.Where(x => x.ParentCategory == null);
foreach(var dataCat in rootDataCategories )
{
//Select the sub-categories for this root category
var children = dataModel
.Where(x => x.ParentCategory != null && x.ParentCategory.Name = cat.Name)
.Select(y => new CategoryViewModel() { CategoryName = y.CategoryName })
.ToList();
var viewCat = new CategoryViewModel()
{
CategoryName = dataCat.CategoryName,
SubCategories = children
};
model.Add(viewCat);
}
return model;
}
Then your view:
<h1>Category Directory</h1>
#foreach(var category in Model)
{
#Html.Partial("Category", category)
}
Category partial:
<h2>#Html.ActionLink(Model.CategoryName, "Detail", new { Model.CategoryName })</h2>
#if(Model.SubCategories.Count> 0)
{
<p>
#for (var i = 0; i < Model.SubCategories.Count; i++)
{
var subCat = Model.SubCategories[i];
#Html.ActionLink(subCat.CategoryName, "Detail", new { subCat.CategoryName })
#if(i < Model.SubCategories.Count - 1)
{
<text>,</text>
}
}
</p>
}
Note that my current solution only supports 2 levels of categories (as per your wireframe). It could however be easily extended to be recursive.
Related
In my controller I set the items in the ViewBag:
List<ShopItemModel> items = new List<ShopItemModel>();
/* populate my items */
ViewBag.Items = items;
So on the cshtml i run thru the list, but how do I connect it so on postback sets the argument of the Post method in the controller?
The CSHTML:
#model Models.ShopItemModel
<h2>Webshop</h2>
#foreach( var item in ViewBag.Items)
{
using (Html.BeginForm())
{
<p>#item.Name</p> <!-- List the item name, but not bounded? -->
#Html.LabelFor(model => model.Name, new { Name = item.Name }) <!-- outputs just "Name", not the items name -->
<input type="submit" value="Buy" />
}
}
The post version of the method in the controller:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(ShopItemModel m)
{
return View();
}
But how do I fix this binding? So I fetch the selected item from the list?
In your view:
using (Html.BeginForm())
{
for (int i = 0; i < Model.Count; i++)
{
#Html.LabelFor(model => model[i].Name)
}
}
This will produce html controls like this:
<input name="ShopItemModel[3].Name" ...
If you're using this in a form, in your controller, iterate over the POSTed model data:
foreach (var item in model)
{
... do something to each item
}
You can use a foreach loop in the view rather than a for loop, example here
I would like to pass a value from a link to a View and display the fields of the single record on the page.
Lets say I have #Html.ActionLink(item.Title, "Article/"+#item.ID, "News") which outputs /News/Article/1, I would need a Controller called NewsController with a /News/Article View.
I already have the following:
NewsController:
namespace WebApplication1.Controllers
{
public class NewsController : Controller
{
private WebApplication1Entities db = new WebApplication1Entities();
public ActionResult Article()
{
var articleModel = (from m in db.News where (m.Id == 1) && (m.Active == true) select m);
return View(articleModel);
}
[ChildActionOnly]
public ActionResult LatestNews()
{
var latestModel = (from m in db.News where (m.Id != 1) && (m.Active == true) select m);
return View(latestModel);
}
}
Not sure if I should use FirstOrDefault() as it can only be one record as the Id is unique, but unsure how to reference item objects inside the View without an IEnumerable list. At present the Id is set to 1 but I would like the recordset to reflect the Id passed.
Not sure what code to put inside the View, Article though, here is what I have so far:
Article.cshtml
#model IEnumerable<WebApplication1.Models.News>
#foreach (var item in Model) {
ViewBag.Title = #item.Title;
<div class="row">
<article class="span9 maxheight">
<section class="block-indent-1 divider-bot-2">
<h2>#item.Title</h2>
#item.Summary
#item.Content
</section>
</article>
<article class="span3 divider-left maxheight">
<section class="block-indent-1">
<h2>Latest News</h2>
#{ Html.RenderAction("LatestNews", "News"); }
</section>
</article>
</div>
}
LatestNews.cshtml
#{ Layout = null; }
#model IEnumerable<Shedtember.Models.News>
<ul class="nav sf-menu clearfix">
#foreach (var item in Model)
{
#Html.MenuLink(item.Title, "Article/"#item.ID, "News")
}
</ul>
This works for Id 1 but this needs to be dynamic.
Any help would be much appreciated :-)
In your RouteConfig class map a route as follows:
routes.MapRoute("Article", "Article/{id}", new {controller = "News", action = "Article"});
then in your Article method you can add and use the id parameter as follows:
public ActionResult Article(int id)
{
var articleModel = (from m in db.News where (m.Id == id) && (m.Active == true) select m);
return View(articleModel);
}
I am updating product Quantity by Update button, after clicking on update button page is reloading, instead of reloading that page i want to update that "cartUpdatePanel" table area only by Ajax
My View is
using (Html.BeginRouteForm("ShoppingCart", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table id="cartUpdatePanel" class="table_class" cellpadding="0" cellspacing="0">
#foreach (var item in Model.Items)
{
<tr style="background: #f3f3f3;">
<td>
<input type="submit" name="updatecartproduct#(item.Id)" value="Update Cart" id="updatecartproduct#(item.Id)" />
</td>
</tr>
}
}
My Controller action is, by which i am updating Product Quantity
[ValidateInput(false)]
[HttpPost, ActionName("Cart")]
[FormValueRequired(FormValueRequirement.StartsWith, "updatecartproduct")]
public ActionResult UpdateCartProduct(FormCollection form)
{
if (!_permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart))
return RedirectToRoute("HomePage");
//get shopping cart item identifier
int sciId = 0;
foreach (var formValue in form.AllKeys)
if (formValue.StartsWith("updatecartproduct", StringComparison.InvariantCultureIgnoreCase))
{
sciId = Convert.ToInt32(formValue.Substring("updatecartproduct".Length));
break;
}
//get shopping cart item
var cart = _workContext.CurrentCustomer.ShoppingCartItems
.Where(x => x.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
var sci = cart.Where(x => x.Id == sciId).FirstOrDefault();
if (sci == null)
{
return RedirectToRoute("ShoppingCart");
}
//update the cart item
var warnings = new List<string>();
foreach (string formKey in form.AllKeys)
if (formKey.Equals(string.Format("itemquantity{0}", sci.Id), StringComparison.InvariantCultureIgnoreCase))
{
int newQuantity = sci.Quantity;
if (int.TryParse(form[formKey], out newQuantity))
{
warnings.AddRange(_shoppingCartService.UpdateShoppingCartItem(_workContext.CurrentCustomer,
sci.Id, newQuantity, true));
}
break;
}
//updated cart
cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(x => x.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
var model = PrepareShoppingCartModel(new ShoppingCartModel(), cart, true, false, true);
//update current warnings
//find model
var sciModel = model.Items.Where(x => x.Id == sciId).FirstOrDefault();
if (sciModel != null)
foreach (var w in warnings)
if (!sciModel.Warnings.Contains(w))
sciModel.Warnings.Add(w);
return View(model);
}
How i will achieve to update "cartUpdatePanel" table area after clicking on update button by ajax
Thanx in Advance
Please consider using Ajax.BeginForm helper to create the form. You can use AjaxOptions to specify callback code to capture server output and do whatever you want (including injecting it to a div, table, field set ..)
Using the Ajax.BeginForm is very easy
#using (Ajax.BeginForm(
"name_of_the_action",
new AjaxOptions {
OnSuccess = "processServerResp",
HttpMethod = "POST"},
new {enctype="multipart/form-data"})
){
// rest of the form code
}
Now using javascript, implement processServerResp as a function which takes a single parameter. This parameter will contain what ever values passed from the server to the client. Assuming the server is returning html, you can use the following code to inject it into a container with the id of id_fo_the_div
function processServerResp(serverData){
$(‘#id_fo_the_div’).html(serverData);
// or inject into a table ..
}
You can tap into other interesting features provided by AjaxOptions and do very interesting things.
A good article on Ahax.BeginForm http://www.blackbeltcoder.com/Articles/script/using-ajax-beginform-with-asp-net-mvc
Happy coding
I want to create a layout like the User page on Stack Overflow where there is a view (the parent view) at the top of the page and then content in tabs, each with it's own view (child views).
When I hover over each of the tabs on the User page in SO it looks like they are pointed at the user controller and are being sent the tab name in the query string to render the appropriate tab content.
I believe I can achieve this using a layout with a section defined in the parent view. The section would be the child view, but I don't know how I would tell the section which view or partial view to show.
I have not been able to find anything useful on the web. Can someone tell me how to do this or at least point me in the right direction?
Thanks in advance!
Edit: Thanks to #Mystere's help I was able to come up with the solution below in case anyone else is trying to do the same thing.
HTH
Final Solution:
Controller Actions
public ActionResult Details(int id, string tab = null)
{
ViewBag.Jobid = id;
ViewBag.Tab = tab ?? "Services";
var viewModel = getJobRecordDetails(id);
return View(viewModel);
}
public ActionResult JobInfo(int id, string tab)
{
ViewBag.Jobid = id;
ViewBag.Tab = tab;
if (tab == "Services")
{
var viewModel = getServices(id);
return View("Services", viewModel);
}
if (tab == "Equipment")
{
var viewModel = getEquipment(id);
return View("Equipment", viewModel);
}
if (tab == "Personnel")
{
var viewModel = getPersonnel(id);
return View("Personnel", viewModel);
}
return View("Error");
}
Parent View
#model MyApplication.Models.JobViewModel
#{
ViewBag.Title = "Details";
}
<h2>Job Details</h2>
...
#* Child View Action *#
#Html.Action("JobInfo", new { id = ViewBag.Jobid, tab = ViewBag.Tab })
Child View
#model MyApplication.Models.ServicesViewModel[]
#{
ViewBag.Title = "Services";
Layout = null;
}
#* Submenu Navigation *#
#{
Html.RenderPartial("SubMenu");
}
<h2>Services</h2>
Services here...
Subnavigation Partial View
<div id="submenucontainer">
<ul id="submenu">
<li class="#Html.ActiveTab("Job","JobInfo","Services")">Services </li>
<li class="#Html.ActiveTab("Job","JobInfo","Equipment")">Equipment</li>
<li class="#Html.ActiveTab("Job","JobInfo","Personnel")">Personnel</li>
</ul>
ActiveTab Helper
public static string ActiveTab(this HtmlHelper helper, string controller, string action, string tab)
{
var classValue = "";
var currentController =
helper.ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
var currentAction =
helper.ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
var currentTab = helper.ViewContext.Controller.ValueProvider.GetValue("tab").RawValue.ToString();
if (currentController == controller && currentAction == action && currentTab == tab)
classValue = "selected";
return classValue;
}
It is unlikely they are using a section for that. sections are used primarily in layout pages (the equivelent of master pages).
More than likely, they just have multiple views, and they pass whichever view is appropriate to the View() method. They might use partial views, or MVC templates to render the tab areas, so that common code is factored out.
Edit:
As requested, code sample:
In action method:
public ActionResult Dashboard(string tab) {
if (tab == "summary")
ViewBag.Tab = "~/Views/Dashboard/Summary.cshtml";
if (tab == "activity")
ViewBag.Tab = "~/Views/Dashboard/Activity.cshtml";
return View()
}
in Dashboard.cshmtl
... your parent view
#Html.Partial(ViewBag.Tab)
... your footer
It's not rocket science. There are so many ways to do this it doesn't take much thought to come up with one of them.
I would like to sort the item I'm getting in my view and put them in a different divs according to the category they belong
In my table I have items the belong to different categories (cosmetics_perfumes, cosmetics_makeup …)
Something like after I'm getting
#foreach (var item in Model)
{
To sort it here in same way
(I hope I'm clear )
If you want to do this in your view, then you can use a foreach statement for each of the categories.
<div id="perfumes">
#foreach (var perfume in Model.Where(i => i.Category == "cosmetics_perfumes"))
{
<p>#perfume</p> #*Display each item *#
}
</div>
<div id="makeup">
#foreach (var makeup in Model.Where(i => i.Category == "cosmetics_makeup"))
{
<p>#makeup</p>
}
</div>