ASP.NET MVC - MasterPageView and RenderPartials - Confusion - asp.net-mvc

I'm a little confused with trying to do bring a list of Categories into a navigation bar on a MasterPageView in the latest release of the ASP.NET MVC framework.
I have 0 experience with Partials so far (this adds to the confusion).
Should I use this variant of the RenderPartial?
HtmlHelper.RenderPartial(string partialViewName, object model)
I wasn't able to find any good examples of this method. By convention there is no model associated with the MasterPageView right? So what is the proper way to push or pull data into a "partial" from the MasterPageView?
Assuming that this method is absolutely going down the wrong path:
<div id="navigation">
<%
CategoryRepository cr = new CategoryRepository();
IList<Category> lst = cr.GetCategories();
Html.RenderPartial("NavBar", lst);
%>
</div>

Do you not want your masterpage to have viewdata? You could solve it by having a base view data class that ALL your other viewdata classes inherit from...
BaseViewData.cs - this is a viewdata class that all other viewdata classes will inherit from
public class BaseViewData
{
public string Title { get; set; }
public string MetaKeywords { get; set; }
public string MetaDescription { get; set; }
IList<Category> NavCategoryList { get; set; }
}
Now in your Site.Master page simply have
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage<BaseViewData>" %>
<title><%=ViewData.Model.Title %></title>
<meta name="keywords" content="<%=ViewData.Model.MetaKeywords %>" />
<meta name="description" content="<%=ViewData.Model.MetaDescription %>" />
<%= Html.RenderPartial("NavBar", ViewData.Model.NavCategoryList) %>
This could significantly impact your application architecture, but its not necessarily a bad thing.
HTHs,
Charles

public ActionResult NavBar()
{
CategoryRepository cr = new CategoryRepository();
IList<Category> lst = cr.GetCategories();
return View(lst);
}
on your partial call
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%# Import Namespace="app.Models" %>
and do all your rendering ui here
<div id="navigation">
<%
Html.RenderPartial("NavBar");
%>
</div>
you can do ActionResult calls in your controllers

I would say that since it's the Master Page you would probably have to store your data that you are passing in ViewData with a string key. If it was a regular view page it would be better to have a strongly typed page, but this is a different case. So you would probably do something this in your controller:
ViewData["MasterPageData"] = FunctionToGetData();
And then on the Master Page something like this:
<%
if (ViewData["MasterPageData"] != null)
{
Html.RenderPartial("ControlName.ascx", ViewData);
}
%>
Then in the control, process like you would on a normal view page:
<% var categories = (CastIfNeeded)ViewData["MasterPageData"]; %>
process as normal...
I haven't had to pass data to a master page yet, but that's how I would think you'd do it. More info here.
EDIT: Changed it around a little to reflect what I'm doing in my current project.

I would use Html.RenderAction() instead and return a partial view from it.

Related

_Layout and Partial View

Using an MVC5 application and I am trying to load a model within a partial view that is also within the _layout page. This doesn't seem to work as it conflicts with other models loaded up in different views.
I found an alternative with ViewBags, but it's messy and I don't think it's the best approach. Is there a way to load up a partial view within a model that's inside the _layout page so the model loaded from the partial view doesn't conflict with another model?
Updated:
What I'm trying to do is this:
In the _layout page. I'm trying to use an image carousel which is supplied by bootstrap to be interactive with the user (so the user can change the images, titles, and sub-titles).
I created a model to store the data, such as the title, etc. :
public class BannerEditor
{
public int ID { get; set; }
[Display(Name="Title")]
[StringLength(150)]
public string title { get; set; }
[Display(Name = "Sub-Title")]
[StringLength(300)]
public string subTitle { get; set; }
[Display(Name = "Image Path")]
public string imgPath { get; set; }
[Display(Name= "Starting Banner")]
public int startBanner { get; set; }
}
Then for my partial View I wrote some code and tried to load the model.:
#model IEnumerable<webby.Models.BannerEditor>
#foreach (var item in Model)
{
if (item.startBanner == 1)
{
<div class="item active">
<img src=#item.imgPath alt="...">
<div class="carousel-caption">
<h3>#item.title</h3>
<p>#item.subTitle</p>
</div>
</div>
}
else
{
<div class="item">
<img src=#item.imgPath alt="...">
<div class="carousel-caption">
<h3>#item.title</h3>
<p>#item.subTitle</p>
</div>
</div>
}
}
then in my _Layout page, I just added the Partial.
<div class="carousel-inner">
#Html.Partial("BannerLoad")
Here is the controller:
public ActionResult BannerLoad()
{
return PartialView(db.BannerEditors.ToList())
}
It gives me an error stating that it cannot load the Articles model into my partial view. The model that it needs to load is the BannerEditor. Since my _layout is loaded into every page, and the partial view is loading a model. The partial view's model conflicts with every other loaded model. The models name is "Articles".
Is there a way around this?
Use child actions for this kind of thing. They're like partial views, but they get their own context, allowing you to fetch and work with whatever model you need to without affecting the rest of the page:
Controller
[ChildActionOnly]
public ActionResult BannerLoad()
{
var banners = db.BannerEditors.ToList();
return PartialView(banners);
}
BannerLoad.cshtml
#model IEnumerable<Namespace.To.BannerEditor>
<!-- HTML to display your banners -->
_Layout.cshtml
#Html.Action("BannerLoad");
All that looks pretty similar to what you already have, but there's some key differences:
Partials don't work with actions, that's actually what makes a child action a child action and not a partial. It seems in your current code that you're expecting Html.Partial to render your BannerLoad action, but it will never do that. It will only dump the content from BannerLoad.cshtml onto the page, which because it never got fed an appropriate model, will cause an error.
Partials don't have their own context (because they don't work within a separate action), so they must receive their model from the parent view. If you don't pass a model in (which you aren't), they are automatically passed the "current" model. This will be whatever model the view the main action is using and will obviously change action to action. You cannot set a model on _Layout.cshtml, for example, and have that passed in, as that's not the origin point.
Even if you could set the model on something like _Layout.cshtml, that would only work for that one partial. If you had any other partials, you're still out of luck.

Client Side Validation fails when moving to viewmodel

This seems to a common question for lots of reasons that do not seem to apply to this situation. I have create page using ASP.NET MVC 2 and I was using a strongly typed view to a class generated from DataEnities framework.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC_EDI.Models.wysCustomerEndPoint>"" %>
I made validation class that I bound back to the the data class.
[MetadataType(typeof(EndPointValidation))]
public partial class wysCustomerEndPoint
{
}
[Bind()]
public class EndPointValidation
{
[Required(ErrorMessage = "Please enter the end point name")]
public string CustName { get; set; }
And I was able to use client side validation on my create page. I had a requirement to add a dropdown list box on the create page, so I switched my view to use a viewmodel instead of the data class I was using.
public class CreateEditCustomerEndPointsViewModel
{
public wysCustomerEndPoint CustomerEndPoint {get; set;}
public List<SelectListItem> DefaultLocationList { get; set; }
}
and here is the view header using the new viewmodel.
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MVC_EDI.ViewModles.CreateEditCustomerEndPointsViewModel>" %>
But now when this view gets loaded I am getting an error that my formElement is null when it tries to set a value ? I error out here inteh MicrosofyMvcValidation.js file and the formElement array is null.
formElement['__MVC_FormValidation'] = this
I suspect I need to add some sort of data annotation or attribute to either my view model or something like that. But I am not sure where? And surprisingly it seems to work out just fine in FireFox 5 but bombs in IE9?
Edit: thanks for the reply. Yes I believe I am instantiating the object before adding to the ViewModel and using the Html.Helper objects? Here is the code.
wysCustomerEndPoint ep = new wysCustomerEndPoint();
ep.BuyerID = id;
var viewModel = new CreateEditCustomerEndPointsViewModel()
{
CustomerEndPoint = ep
};
return View(viewModel);
and in the view
<div class="editor-label">
<%: Html.Label("Name") %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.CustomerEndPoint.CustName) %>
<%: Html.ValidationMessageFor(model => model.CustomerEndPoint.CustName) %>
</div>
cheers
bob
You're maybe doing this, but without seeing the relevant bits of code I don't want to assume. So, make sure you are instantiating the wysCustomerEndPoint object and sending to your view from the Controller method. Also that you are using the Html Helpers for the input elements that you are validating on. Eg.
Html.TextboxFor(model => model.wysCustomerEndPoint.CustName)

Multiple partial views on one main asp.net

trying to put a strongly typed partial view on a homepage in asp.net but it wont seem to work it, here is my code
new to asp.net and partial views.
Controller :
public ActionResult VenuePartial()
{
ViewData["Message"] = _entities.VenuePartialList();
return View();
}
Repository :
public IEnumerable<Venue> VenuePartialList()
{
var list = from s in _entities.Venue
orderby s.name ascending
select s;
return list.ToList();
}
IRepository :
IEnumerable<Venue> VenuePartialList();
Index Page :
<%Html.RenderPartial("~/Views/Venue/VenuePartial.ascx");%>
Any help would be grateful asap please
regards T
Maybe you need to pass a model to this partial:
<% Html.RenderPartial("~/Views/Venue/VenuePartial.ascx", ViewData["Message"]); %>
And by the way WTF are you using ViewData["Message"] to pass a model instead of using a model and a strongly typed view:
public ActionResult VenuePartial()
{
return View(_entities.VenuePartialList());
}
and then:
<% Html.RenderPartial("~/Views/Venue/VenuePartial.ascx", Model); %>
This obviously assumes that your partial is strongly typed to IEnumerable<Venue>. If it is typed to a single Venue you might also consider using Editor/Display Templates. So in your main view:
<%= Html.DisplayForModel() %>
and in the corresponding display template (~/Views/Shared/DisplayTemplates/Venue.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.Venue>" %>
<span>
<%= Html.DisplayFor(x => x.SomePropertyOfVenue) %>
</span>
and now the display template will be rendered for each item of the model collection.

can you post complex objects from form to controller in asp.net mvc

i see there are solutions using different model binders like castl but i didn't know if the basic default model binder supported nested complex objects when i am posting a form to a controller.
I think you can if I understand your question.
In the name of my field I not only put the property name but object as well.
So if I have a "Person" object that contains an "Address" object that contains a "State" field I would have as the name "Person.Address.State" and that seems to resolve just fine in my controller.
<%= Html.TextBox("Person.Address.State", Person.Address.State....
Is this what you are asking?
EDIT
It does work and here is the code to get it to work.
namespace DoMyWork.Controllers
{
public class test
{
public string value { get; set; }
}
public class testParent
{
public test test { get; set; }
}
public class SearchController : Controller
{
public ActionResult ViewUserControl1(testParent test)
{
UpdateModel(test);
return View(test);
}
SNIP
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<DoMyWork.Controllers.testParent>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
ViewUserControl1
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>ViewUserControl1</h2>
<% using( Html.BeginForm()){ %>
<%= Html.TextBox("test.value", Model.test.value) %>
<input type="submit" value="sdf" />
<%} %>
</asp:Content>
I had the same problem and I found a similar question that helped a lot of people to solved this: Complex object and model binder ASP.NET MVC, but it didn't solve my problem.
I realized that the problem was caused because my inputs were disabled (I was disabling them with JQuery on document ready) as you can see it here: How do I submit disabled input in ASP.NET MVC?. At the end I used read-only instead of disabled attribute.

Returning data from controllers to views in asp.net mvc

Is it possible to return a complex type from a controller to a view in asp.net mvc? All the examples I have looked at so far demonstrate passing simple intrinsic types like int, string....
You can pass any object type to the view using the ViewData Dictionary.
Just put in your controller:
ViewData["example"] = (YourObject)data;
And then in your view:
<%= ((YourObject)ViewData["example"]).YourProperty %>
And if you want to pass your object as your View model then:
return View("viewname", (YourObject)data);
And make sure your view looks like this:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<YourObject>" %>
You can create a viewmodel that's then used in the strongly typed view. You can check out this blogpost by Stephen Walther that explains it. I started out just dumping stuff in viewdata, but that gets confusing pretty quickly ;).
Use a ViewModel for your page.
you could use a view model containing both complex and simple objects, for example:
public class MyComplexViewModel
{
public Address UserAddress { get; set;}
public List<string> ValidZipCodes { get; set; }
public string Message { get; set; }
}
If your view inherits the generic ViewPage with something like this
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyComplexViewModel>" %>
you could then in the view use the view model as Model.:
<%= Html.Encode(Model.UserAddress.SomeAddressProperty) %>
<%= Html.Encode(Model.ValidZipCodes.Count) %>
<%= Html.Encode(Model.Message) %>

Resources