If I use the following Controller method:
public ActionResult Menu()
{
// do stuff...
return PartialView("viewName", navLinks);
}
calling the partial view in _Layout.cshtml like this:
<div id="categories">
#{ Html.Action("Menu", "Nav"); }
</div>
With the following ASCX partial view:
<%# Control Language="C#"
Inherits="ViewUserController<IEnumerable<MyDataType>>" %>
<% foreach(var link in Model) { %>
<%: Html.Route.Link(link.Text, link.RouteValues) %>
<% } %>
everything works fine. Yay.
BUT, if I use either of the following RAZOR partial views:
#model IEnumerable<MyDataType>
#foreach(var link in Model){
Html.RouteLink(link.Text, link.RouteValues);
}
or...
#model IEnumerable<MyDataType>
#{
Layout = null;
}
#foreach(var link in Model){
Html.RouteLink(link.Text, link.RouteValues);
}
I get nothing. there's no exception thrown, I just don't get anything rendered. I know the problem isn't with the controller method (it works just great with the ASCX partial view).
What's going on here?
Try changing this:
#foreach(var link in Model){
Html.RouteLink(link.Text, link.RouteValues);
}
to this:
#foreach(var link in Model){
#Html.RouteLink(link.Text, link.RouteValues);
}
It looks like without the # the method is being called, but the return value is just being dscarded. Putting the # causes it to be written in the response.
The RenderAction method writes the action directly to the view and returns void.
The Action method returns the action's contents but doesn't write anything to the view.
Writing #something will print the value of something to the page.
You cannot write #Html.RenderAction, since RenderAction doesn't return anything.
Writing Html.Action(...) (without #) calls the method normally, but doesn't do anything with its return value.
OK, Changing the way the it was called from _Layout.cshtml worked...
<div id="categories">
#Html.Action("Menu", "Nav");
</div>
It is important to note, that #Html.RenderAction DOES NOT work for me. I'd really love some explanation here, because right now, learning Razor is frustrating me as there is little documentation, and problems like these which should take minutes to resolve, are eating up way too much of my time.
Related
I have a pretty simple scenario, Model for my view is a List.
Loop through List like
#foreach(CustomObject obj in Model)
{
Html.Partial("_TrackingCustomObject",obj)
}
So i was expecting to have number of partial views according to my list.
Partial View has been developed accordingly.
There is no error on page. It just does not show any data that is supposed to display by partial views.
What is the reason of not showing any data?
You are missing an #:
#foreach(CustomObject obj in Model)
{
#Html.Partial("_TrackingCustomObject", obj)
}
But why writing foreach loops when you can use editor/display templates? Like this:
#model IEnumerable<CustomObject>
#Html.EditorForModel()
and then simply define the corresponding editor template (~/Views/Shared/EditorTemplates/CustomObject.cshtml) that will automatically be rendered for each element of your model:
#model CustomObject
<div>
#Html.EditorFor(x => x.Foo)
</div>
Simple and conventional :-)
You're missing the Razor symbol #:
#foreach(CustomObject obj in Model)
{
#Html.Partial("_TrackingCustomObject",obj)
}
Also make sure your partial view is using the object type CustomObject as the Model.
#model MyProject.Models.CustomObject
<h1>Yeah we're in a partial! #Model.SomeProperty </h1>
To try and drill down to where the error is, try placing some static text inside the PartialView.
<p>Some text</p>
If your collection has 10 items, then you should see 10 of these paragraphs. Next once this works, focus on displaying some property in each item.
#model MyProject.Models.CustomObject
<p>Some text</p>
<p>#Model.SomeProperty</p>
When you are creating html form using #Html.BeginForm() you have to wrap the remaining stuf inside a <div> or other container else the html elements won't get rendered.
Ex.
this won't work
#using(Html.BeginForm())
{
Html.EditorFor(m => m.Name)
}
this will work
#using(Html.BeginForm())
{
<div>
#Html.EditorFor(m => m.Name)
</div>
}
Bit late in the day, but this worked for me in MVC 4:
#foreach (var p in #Model.RelatedCards)
{
Html.RenderPartial("_ThumbPartial", p);
}
Try this:
#Html.RenderPartial("_TrackingCustomObject",obj)
This is too old but someone can use it.
#foreach(CustomObject obj in Model)
{
<text>
Html.Partial("_TrackingCustomObject",obj)
</text>
}
My app has modules that can be turned on and off and these modules are contributing to a view via Html.Partial calls. When the page posts back to the controller I want to have the modules take care of their individual models using something like TryUpdateModel that the controller has. Problem is that TryUpdateModel is a protected method and not accessible from outside the controller.
How can I do something like Controller.TryUpdateModel from a class outside of the controller?
If I am reading this right, it sounds like you are wanting a partial view to update itself.
I have done something similar with some jQuery, by calling an action and returning a partial view inside of a partial view. Inception?
Simple Example. - really simple
_partialViewStart.cshtml
<div id="partialFillerResult">
</div>
<script type="text/javascript">
$(document).ready(function() {
loadPartialViewFiller();
});
function loadLatestTribes() {
$("#partialFillerResult").load("#Url.Action("PartialViewFiller", "Home")").fadeIn("slow");
setTimeout(loadPartialViewFiller, 5000);
}
</script>
HomeController.cs
public ActionResult PartialViewFiller()
{
var yourModel = new ExpandoObject();
if (yourModel == null) return PartialView("_empty");
return PartialView("_partialViewFiller", yourModel);
}
_partialViewFiller.cshtml
#model dynamic
<div class="objectWrapper">
<p>
#Model.Name
</p>
</div>
I have a ASP.Net MVC 2 partial view like the one below,
FORM 1:
<div id="d1">
<% using (Ajax.BeginForm("ManageSources", "Sources",
saveAjaxOptions))
{ %>
... all this form's html markup goes here
<div id="src_Parameters"></div>
<% } %>
</div>
Form 2
<% using (Ajax.BeginForm("FetchParameters", "Sources",
fetchAjaxOptions))
{ %>
hidden fields to send values to the action method go here
.. button to post this form
<% } %>
Now, in the fetchAjaxOptions, i have given the target div to be src_Parameters, which resides inside the form1, when i post the second form, i am being returned a partial view as the only view page, instead of populating the results in the src_Parameters div.
How do i accomplish this. Actually the results of the FetchParameters ajax call should be able to be posted for the ManageSources ajax call.
Where is the problem or will nesting the forms workout since this is using ajax forms.. Kindly suggest me the right procedure to do this task.
You haven't posted your server side code, but I suspect you have forgotten to have set the return type to be a partial view.
public PartialViewResult FetchParameters()
{
//do some stuff
return PartialView(“_ViewName”, viewModel)
}
It could also be that you fotgot to add a reference to the Microsoft Ajax
<script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script>
I have a single view that is used by two Controller Actions.
My Controller:
AccountController {
...
ActionResult LogOn() {
return View()
}
[HttpPost]
ActionResult LogOn(LogOnModel model) {
return View(model)
}
}
My View:
<% if (!String.IsNullOrEmpty(Model.UserName)) { %>
<div class="username"><% Response.Write(Model.UserName); %></div>
<% } %>
Of course, the problem with the above code is that I get an error "Object Reference not set to an instance of an object" on the line that references Model.UserName.
What is the best way to my view to support both Actions? I can replace the HttpGet LogOn method with:
ActionResult LogOn() {
result View(new LogOnModel());
}
That works, but it doesn't seem very elegant and I'm sure an empty model will break some more complex models that I will need to create later on. Is there a better way? Thanks!
What is the best way to my view to support both Actions?
If a view is strongly typed to a view model (which is what absolutely all your views should be) you should make sure that all your controller actions serving those views (which is pretty much all your controller actions in your application) are passing a view model to those views.
Which is pretty much bla-bla which translated into source code pretty basically means this:
ActionResult LogOn() {
return View(new LogOnModel())
}
That works, but it doesn't seem very elegant and I'm sure an empty
model will break some more complex models that I will need to create
later on.
That's the correct way. Don't worry. You ain't gonna break anything. It's by not providing a view model to your views that you are breaking stuff.
Also as a side note you should absolutely never use Response.Write in a view. So instead of:
<% Response.Write(Model.UserName); %>
you totally want:
<%= Html.DisplayFor(x => x.UserName) %>
or:
<%: Model.UserName %>
but personally I prefer the DisplayFor helper since it will take care of any metadata.
You can either return a different view or as you have done, return a new model.
As noted by other commenters, your Controller should support the strong-typeness of your view. But if you insist on proceeding with the anti-pattern. Replace this:
<% if (!String.IsNullOrEmpty(Model.UserName)) { %>
<div class="username"><% Response.Write(Model.UserName); %></div>
<% } %>
with this:
<% if (Model!= null && !String.IsNullOrEmpty(Model.UserName)) { %>
<div class="username"><% Response.Write(Model.UserName); %></div>
<% } %>
I just started to learn MVC and am trying to understand how it works.
I don't want to send users to different views for all edit, insert and list operations.
In my sample application a View contains a list of items and below the list there is a form (for inserting new items) with action "{Controller}/Create" but there is no Create View.
When a user inserts a new item it posts to the Create action with httpverb post and creates the item and returns back to the List action with RedirectToAction method.
But I can not show any message(error, information etc) to the user in this style because I can not pass data between Create action and List action. How can I do that?
You need to use Post Redirect Get PRG pattern.
Please read this Use PRG Pattern for Data Modification section in this blog post by Kazi Manzur Rashid.
http://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx
This approach uses TempData to maintain ModelState data between redirects.
[HttpPost, ValidateAntiForgeryToken, ExportModelStateToTempData]
public ActionResult Create(FormCollection form)
{
Product p = new Product();
if (TryUpdateModel<IProductModel>(p))
{
productRepository.CreateProduct( p );
}
else
{
// add additional validation messages as needed
ModelState.AddModelError("_generic", "Error Msg");
}
return RedirectToAction("Index");
}
And here is your Index action method.
[ImportModelStateFromTempData]
public ActionResult Index()
{
IList<Product> products = productRepository.GetAll();
return View("Index", products);
}
And here is your Index view.
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IList<Product>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Products</h2>
<% foreach (var p in Model) { %>
<div><%= Html.Encode( p.ProductName ) %></div>
<% } %>
<%= Html.ValidationSummary("Please correct the errors", new { id = "valSumCreateForm" }) %>
<% using (Html.BeginForm("Create", "Product")) { %>
Product Name: <%= Html.TextBox("ProductName") %>
<%= Html.AntiForgeryToken() %>
<% ViewContext.FormContext.ValidationSummaryId = "valSumCreateForm"; %>
<% } %>
</asp:Content>
The ImportModelStateFromTempData
and ExportModelStateToTempData
attributes helps transfer model
state errors between redirects. This
<% ViewContext.FormContext.ValidationSummaryId = "valSumCreateForm"; %> associates the MVC Form with its corresponding Validation Summary.
You can check another answer by me on this here as well.
ViewModel with SelectList binding in ASP.NET MVC2
Let me know if you have any question.
-Soe
Most MVC frameworks have the ability to temporarily store a small bit of data just through the next request, for just this purpose. In ASP.NET MVC its called TempData, in Rails it's called :flash, etc.
This article explains how to use TempData:
One of the more annoying things to
deal with in Web programming is errors
on a form. More specifically, you want
to display error messages, but you
want to keep the previously entered
data. We've all had the experience of
making a mistake on a form that has 35
fields, only to be presented with a
bunch of error messages and a new,
blank form. The MVC Framework offers TempData as a place to store the previously entered information so that the form can be repopulated. This is
something that ViewState actually made
very easy in Web Forms, since saving
the contents of controls was pretty
much automatic. ... TempData is a dictionary,
much like the untyped ViewData.
However, the contents of TempData only
live for a single request and then
they're deleted.