ASP.NET MVC Database Driven Menu in shared view - asp.net-mvc

I need some guidance on inserting a menu in the _layout.cshtml file. I have hit two problems:
1) Even when I create an additional model to include two data models, I am unable to pass both the models to the layout file
eg:
Model:
public class IndexModel
{
public tblMenu tblMenu { get; set; }
public tblSite tblSite { get; set; }
}
I need info from the Menu table and the site table on the same page.
2) When I create a partial view to pass the menu data I continually get exceptions telling me that I can't use the model in this way.
My Partialview:
#model mvcSPS.Models.IndexModel
<li>#Model.tblMenu.MenuName</li>
My Controller:
public ActionResult _menu()
{
return PartialView(db.IndexModels.ToList());
}
My _layout.cshtml
<ul id="navigation">
#foreach (var item in Model)
{
#Html.Partial("_menu")
}
</ul>
I have trawled the net and to be quite frank.. I am having a really difficult transition from ASP classic (yes I know) to ASP.net and MVC.
Your gentle guidance would be much appreciated.
Thanks
Andrew

change your #Html.Partial in your _layout.cshtml to call the controller function and render the result of the Action method.
#foreach (var item in Model)
{
Html.RenderAction("_menu", "Home");
}
note: you shouldn't need a prepending '#' since it's in the context of the foreach loop
EDIT: Based on my comment suggestion below
HomeController:
public ActionResult Menu() {
return PartialView("_menu", db.IndexModels.ToList());
}
_layout.cshtml
#{Html.RenderAction("Menu", "Home");} //be sure to fully-qualify the controller since it's layout, otherwise it'll look to the current controller based on route values collection
_menu.cstml
<nav>
<ul>
#foreach(var item in Model) {
Html.Partial("_menuItem", item)
}
</ul>
</nav>
_menuItem.cshtml
#foreach(var item in Model) {
<li>
text
#if(item.Children.Any())
{
<ul>
Html.Partial("_menuItem", item.Children)
</ul>
}
</li>
}

Related

Alternatives to Partial Views

There is a requirement to share list items (li) among multiple unordered lists (ul).
The current solution is to create a PartialView for each group of list items to be shared, for example:
#*PartialViewOne*#
<li>item1</li>
<li>item2</li>
<li>item3</li>
#*PartialViewTwo*#
<li>item1</li>
<li>item2</li>
#*ViewOne*#
<ul class="CustomClassONE">#Html.Partial("PartialViewOne")</ul>
#*ViewTwo*#
<ul class="CustomClassTWO">#Html.Partial("PartialViewOne")</ul>
Since there are many list items groups, this will require creating many PartialViews. Not that it is difficult to create them but just looking for more efficent way of accomplishing the same thing. What alternatives are out there for using the above technique?
I would advice to create those lists using Controllers and add them to viewmodels for the pages you use, probably create some class that will return a collection of items on demand and put these items to viewmodel. Then display them using .ComboBoxFor(x=>...)
Something like this:
public ActionResult Index() {
var viewModel = new ViewModel();
viewModel.ListItems = listItemFactory.GetItemsForFirstCase(); //populate items you use in your example as PartialViewOne
return View(viewModel);
}
public ActionResult Search() {
var viewModel = new ViewModel();
viewModel.ListItems = listItemFactory.GetItemsForSecondCase();//populate items you use in your example as PartialViewTwo
return View(viewModel);
}
This way your view code will be much cleaner - you will need 1 partial / DisplayTemplate / EditorTemplate for all cases, and all data can be combined in any way you will need.
If the type of data you want to display in the partial are same, you may create a viewmodel to represent that,
public class MyCustomList
{
public string ListHeader {set;get;}
public List<string> Items {set;get;}
public MyCustomList()
{
Items= new List<string>();
}
}
Then add new properties of this type to your other viewmodels as needed
public class CustomerDetailsVm
{
public string FirstName {set;get;}
public MyCustomList RecentOrders {set;get;}
}
public class ProductDetails
{
public string ProductCode {set;get;}
public MyCustomList SimilarProducts {set;get;}
}
And in your Action methods, you will set your view/action specific values to this property
public ActionResult CustomerDetail(int id)
{
var vm = new CustomerDetailsVm { FirstName = "Shyju" };
vm.RecentOrders = new MyCustomList
{
ListHeader = "Recent Orders",
Items = new List<string>
{
"IPad",
"Beer"
}
};
return View(vm);
}
public ActionResult ProductDetail(int id)
{
var vm = new ProductDetails { ProductCode = "Accord" };
vm.SimilarProducts = new MyCustomList
{
ListHeader = "Similar Products",
Items =new List<string>
{
"Altima",
"Camry"
}
};
return View(vm);
}
And in your views
#model ProductDetails
<h2>#Model.ProductCode</h2>
#Html.Partial("ListPartial",Model.SimilarProducts)
and
#model CustomerDetailsVm
<p>#Model.FirstName</p>
#Html.Partial("ListPartial",Model.RecentOrders)
And your partial view will be strongly typed to our MyCustomList viewmodel
#model MyCustomList
<h1>#Model.ListHeader</h1>
<ul>
#foreach(var item in Model.Items)
{
<li>#item</li>
}
</ul>
This is not an alternative to PartialViews but rather to the way PartialViews are traditionaly used. Tested and was inspired by the following thread. Very interesting approach for extracting static html fragments from a single PartialView.
<!-- ViewOne -->
<ul>
#Html.Partial("SharedPartialView", "ListA")
</ul>
<!-- ViewTwo -->
<ul>
#Html.Partial("SharedPartialView", "ListA")
</ul>
<!-- SharedPartialView that includes all list items -->
#if (Model == "ListA")
{
<li>item1</li>
<li>item2</li>
<li>item3</li>
}
#if (Model == "ListB")
{
<li>item1</li>
<li>item2</li>
}
Another robust alternative as well is to use JQuery to extract html fragments from the SharedPartialView and inject them into the Views:
<!-- LayoutView -->
<!-- load fragments/lists PartialView in a hidden div-->
<div style="display:none">#Html.Partial("SharedPartialView")</div>
<!-- append appropriate fragments to multiple elements using JQuery -->
<script type="text/javascript">
$(document).ready(function () {
var test = $("#ListA").contents();
test.appendTo("#ulOne, #ulTwo");
});
</script>
<!-- ViewOne -->
<ul id="ulOne">
</ul>
<!-- ViewTwo -->
<ul id="ulTwo">
</ul>
<!-- SharedPartialView that includes all lists -->
<ul id="ListA">
<li>item1</li>
<li>item2</li>
<li>item3</li>
</ul>
<ul id="ListB">
<li>item1</li>
<li>item2</li>
</ul>

Object reference not set to an instance of an object in MVC5

I have an MVC5 app, and in the HomeController, I have an ActionResult defined like this:
public ActionResult BlogRSS()
{
var model = new BlogModel();
string strFeed = "http://webmysite.com/feed";
using (XmlReader reader = XmlReader.Create(strFeed))
{
SyndicationFeed rssData = SyndicationFeed.Load(reader);
model.BlogFeed = rssData;
}
return View(model);
}
Then, for this ActionResult, I created a partial view named BlogRSS, which looks like this:
#model MyApp.Models.BlogModel
#{
if (Model.BlogFeed != null)
{
<ul>
#foreach (var post in Model.BlogFeed.Items.ToList().Take(3))
{
<li><a href='#post.Links.First().Uri' target='_blank'>#post.Title.Text</a></li>
}
</ul>
}
}
And my model is defined simply like this:
public class BlogModel
{
public SyndicationFeed BlogFeed { get; set; }
}
So, the point is that I want to call that partial view in my _Layout.cshtml file, but when the website opens I get the error message specified in the title. I guess it is not calling my BlogRSS method at all. I'm calling it in the _Layout.cshtml like this:
<div class="col-md-4">
Blog
<br />
#Html.Partial("BlogRSS")
</div>
How can I solve the problem, and make sure that the corresponding ActionResult is also called before rendering the View?
The problem is that you're putting a call to a partial view which just renders the view without calling the controller and the model passed to that view is null.
There are couple ways how to fix this:
1) use Action instead of Partial
#Html.Action("BlogRSS", "Blog")
2) Define a base ViewModel which you will pass to the each view and put your feed into it.

Dynamic database driven accordion in mvc

I am using ASP.NET mvc4 with razor,i am trying to create accordion control dynamically by reading the values from the database. Could someone please point me to the example code on how to start.
based on the sample of accordion here
here what you can do in your controller
public ActionResult Index()
{
using(var db=new YourDataContext())
{
List<YourTableModel> details=db.YourTable.ToList();
return View(details)
}
}
and in your view assuming that the table you have contains Title and Description data
#model IEnumerable<YourTableModel>
<dl class="accordion">
#foreach(var detail in Model)
{
<dt>#detail.Title</dt>
<dd>#detail.Description</dd>
}
</dl>

Where should I put this code?

Here's the code, written to be written in a controller:
CategoryRepository categoryRepo = new CategoryRepository();
var categories = categoryRepo.FindAllCategories();
ViewBag.Categories = categories;
Now I'd like to use this to create a nice list of Categories dynamically.
<div id="leftnavigationbar">
<ul>
#foreach (var category in ViewBag.Categories)
{
//Create li here.
}
<!-- ActionLink goes: Text, ActionName, Controller -->
<li>#Html.ActionLink("Libros", "Index", "Home")</li>
<li>#Html.ActionLink("Peliculas, Musica & Juegos", "Index", "Anuncios")</li>
<li>#Html.ActionLink("Computadoras", "Index", "Usuarios")</li>
<li>#Html.ActionLink("Bienes Raices", "Index", "Ayuda")</li>
<li>#Html.ActionLink("Bolsa de Trabajo", "Index", "Contacto")</li>
<li>#Html.ActionLink("Deportes y Fitness", "Index", "Contacto")</li>
<li>#Html.ActionLink("Electronicos y Celulares", "Index", "Contacto")</li>
</ul>
</div>
Right now I'm writing this code to the _Layout.cshtml file. But I'd like to know where to write this so it runs always, sort of like a MasterPage.
Any suggestions?
Edit:
It appears that my initial intent isn't possible.
#foreach (var category in ViewBag.Categories)
{
<li>#Html.ActionLink(category.Name, "Index", "Home")</li>
}
Any suggestions on how accomplish what I'm trying to do? Just pull a list of categories and render them using a foreach loop. Then have it placed somewhere so it's viewable on all pages.
As always you start by creating a view model:
public class CategoryViewModel
{
public string CategoryName { get; set; }
}
Then in your controller you fill the view model:
public ActionResult Index()
{
var categories = categoryRepo.FindAllCategories();
var model = MapModelToViewModel(categories);
return View(model);
}
And finally your strongly typed view could use a display template. Obviously the view will be strongly typed to IEnumerable
<ul>
#Html.EditorForModel()
<!-- ActionLink goes: Text, ActionName, Controller -->
<li>#Html.ActionLink("Libros", "Index", "Home")</li>
...
</ul>
And your display template (~/Views/Home/DisplayTemplates/CategoryViewModel.cshtml):
#model YourApp.Models.CategoryViewModel
<li>#Model.CategoryName</li>
As you can see with strongly typed views and display templates you don't even need to write loops in your views.
As an alternative to display templates you could use Html.Action or Html.RenderAction helers. Phil Haack wrote a nice blog post about them. I suspect that you were forced to use the ugly untyped ViewBag because this code is situated in your master template and you don't have a view model. No problem, with Html.Action you could have a specific controller that will do this:
public class CategoriesController: Controller
{
public ActionResult Index()
{
var categories = categoryRepo.FindAllCategories();
var model = MapModelToViewModel(categories);
return View(model);
}
}
And then have a corresponding partial view which will take care of rendering the categories (~/Views/Categories/Index.cshtml):
#model IEnumerable<YourApp.Models.CategoryViewModel>
#Html.DisplayForModel()
And finally use the same display template.
Now in your master page you could simply include this child action:
<ul>
#Html.Action("index", "categories")
<!-- ActionLink goes: Text, ActionName, Controller -->
<li>#Html.ActionLink("Libros", "Index", "Home")</li>
...
</ul>
You're looking for something called a 'partial view'.

asp.net mvc - multiple databound components on a page

Im new to asp.net mvc and just learning the basics right now.
Im wondering how pages with muliple databound items would work with mvc views.
for example say there is a page that lists a bunch of "news articles" from a "NewsArticles" table.
and in the side of the page there is a another list which contains a list of "CaseStudies" for example.
then how would that be achieved in mvc?
You'd create your own view model class:
public MyPageViewModel
{
public IEnumerable<NewsArticles> Articles{get;set;}
public IEnumerable<CaseStudies> CaseStudies{get;set;}
}
Return it as the model in your action:
public ActionResult MyPage()
{
var model = new MyPageViewModel();
model.Articles = ArticleManager.GetArticles();
model.CaseStudies = CaseStudyManager.GetCaseStudies();
return View(model);
}
Then you can use a strongly typed view of type ViewPage<MyPageViewModel>, and output them like this:
<ul>
<% foreach(NewsArticle article in Model.Articles){%>
<li><%=article.Title%></li>
<%}%>
</ul>
<ul>
<% foreach(CaseStudy caseStudy in Model.CaseStudies){%>
<li><%=caseStudy.Title%></li>
<%}%>
</ul>
One option would be to specify the ViewData in the action method:
ViewData["NewsArticles"] = GetNewsAticles();
ViewData["CaseStudies"] = GetCaseStudies();

Resources