I am trying to reuse some code and a partial view seems to be the best way to do this when using MVC.
I have created a partial view (see below) which inherits from IEnumerable.
#model IEnumerable<Models.facility>
<div class="display-field">
#foreach (var facility in Model)
{
<li>
#facility.name
</li>
}
</div>
The view that embeds this view does it like so:
<div class="display-field">
<div> #{Html.RenderPartial("FacilityPartial");} </div>
</div>
So now the problem.
I am getting a null reference error and I can see that the Model variable is null.
Error:
Object reference not set to an instance of an object.
Can somebody advise me whether I am doing the correct thing and where I am going wrong other than the fact it is null?
Use Html.Partial. Consider this example.
Index View (Home)
#{
ViewBag.Title = "Home Page";
//Test model to be passed to the partial view
var products = new List<Product> { new Product{ProductName="Test product 1", ProductId=1234}};
}
#Html.Partial("_TestPV", products)
_TestPV (Partial View)
#model IEnumerable<Product>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
ProductName
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProductName)
</td>
</tr>
}
</table>
Output:
You forgot to pass a parameter to your partial view, thus the null reference. Should be:
#{Html.RenderPartial("FacilityPartial", someIEnumerableVariableHere);}
When you're invoking #{Html.RenderPartial("FacilityPartial");} you provided the name of the partial view but you forgot to include the model as a parameter. This is why you're getting the null reference error because when the view is being rendered it is trying to access the model which you have declared in the view as:
#model IEnumerable<Models.facility>
If you change the invoking line to #{Html.RenderPartial("FacilityPartial", model);} it should work. The view can now act on the model which is being passed into it.
As a side note, the accepted answer by #Jobbert Enamno, uses #Html.Partial as opposed to #Html.RenderPartial which you have used in your question. the difference between these may be confusing you or anyone else viewing this question:
#Html.Partial returns the rendered view as a MvcHtmlString, so you could store this in a variable if you wanted.
#Html.RenderPartial does not return anything i.e. void, and thus outputs straight to the Response stream.
Performance-wise it is generally better to use the latter. See this question for more detailed answers.
Related
I have a view page where I am listing a username and their email address from the database and I was wondering how to display the email so when it is clicked on it opens up the outlook mailbox and sends and email to that address:
Here is my view:
#model IEnumerable<Comtrex_ICU.Models.UserProfile>
#{
ViewBag.Title = "UserTable";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 class="admin-home-link orange-titles">#Html.ActionLink("User Information", "AdminIndex")</h2>
<p> </p>
#foreach (var item in Model)
{
<p>#Html.DisplayFor(modelItem => item.UserName) | #Html.ActionLink("(modelItem => item.Email)")</p>
}
Anyone know the proper syntax?
you're passing your <a> tag into Html.ActionLink as a parameter which is not something that it expects to receive. Instead, you can omit the Html.ActionLink entirely and just build the <a> tag as follows:
<p>#Html.DisplayFor(modelItem => item.UserName) | #item.Email</p>
note that Html.ActionLink will generate the entire <a> tag for you and is used when you'd like to generate a link that will hit an action on one of your controllers so that doesn't really fit with what you're trying to do and is why it isn't needed.
The form:
#Html.ActionLink("View Daily Details", "ViewDaily")
<div class="ca-form-layout">
<table class="ca-index-table" style="margin:10px auto">
<tr class="ca-header-row">
<th class="ca-header-cell" style="width:60px"></th>
<th class="ca-header-cell" style="width:140px">Date</th>
<th class="ca-header-cell" style="width:140px">Payment Total</th>
</tr>
#foreach (var gr in groups)
{
<tr class="ca-table-row">
<td class="ca-table-cell" align="center">#Html.RadioButton("payDate", gr.Key.ToShortDateString())</td>
<td class="ca-table-cell" align="center">#Html.FormatValue(gr.Key, "{0:MM/dd/yyyy}")</td>
<td class="ca-table-cell" align="center">#Html.FormatValue(gr.Sum(p => p.PaymentAmount), "{0:C}")</td>
</tr>
}
</table>
</div>
</div>
From my controller, how do I get the value from the payDate radioButton? I was trying to use FormCollection["payDate"] but wasn't getting any value to come through that way. I know there must be some easy answer, but I can't find it anywhere.
Note: If I replace the radioButton with this:
#Html.ActionLink("View Daily Details", "ViewDaily", new { prmDate = gr.Key })
... the page works perfectly fine so there is nothing wrong with any of the values, routing or controller ... I just can't get that value to pass without specifying it directly in the ActionLink. There are 3 other buttons that all need to work off the RadioButton so I can't simply just replace it with a single button.
Thanks
There's no actual form here, so there's nothing sending that value to the server.
To create a form with form elements (such as a radio button), you'd wrap it in something like this:
#using (Html.BeginForm("ViewDaily", "SomeControllerName"))
{
<!--- Your HTML goes here, including form elements --->
}
Included within that form scope would generally be a submit button, something like:
#using (Html.BeginForm("ViewDaily", "SomeControllerName"))
{
<!--- Your HTML goes here, including form elements --->
<input type="submit" value="View Daily Details" />
}
Which of course you could style to look like whatever you want. If you really want the "submit" to be a link then you'd need to write some JavaScript to turn that request (which is otherwise a GET) into a form POST. But just using a submit button would be considerably easier.
This would wrap your form in the requisite <form> tag so that the browser knows to send the key/value pairs to the server.
I'm following the video on Microsoft's Virtual Academy named "Developing ASP.NET MVC 4 Web Applications Jump Start". In part 5: Integrating Javascript and MVC 4 they start showing off how to use PartialViewResults. I've copied the code exactly as they have in the video, however, I'm getting a different result. They don't show some of the code (SessionController) and it was required for me to figure that part out myself, so maybe that's where I'm messing up.
The problem is that my partial view being called by Html.Action is showing up as plain text instead of the HTML. Like below
I've tried Html.Action, Html.RenderAction, Html.Partial and Html.RenderPartial and all seem to give the same results. Any clue what I might be doing wrong here? I don't want to flood this post with a massive list of code, so I'll post code as requested, if necessary.
EDIT: Requested Razor Code*
Step1:
#model MVC_Tutorial2.Models.Session
<h3>
#Model.Title
</h3>
<div>
#Model.Abstract
</div>
#Html.Action("_GetForSession", "Comment", new { sessionID = Model.SessionID })
Step2:
#model IEnumerable<MVC_Tutorial2.Models.Comment>
<div id="comments>
<ul>
#foreach (var comment in Model) {
<li>#comment.Content</li>
}
</ul>
#using (Ajax.BeginForm("_Submit", "Comment", new AjaxOptions() { UpdateTargetId = "comments" })) {
#Html.AntiForgeryToken()
#Html.Action("_CommentForm", new { SessionID = ViewBag.SessionID })
}
</div>
Step3:
#model MVC_Tutorial2.Models.Comment
#Html.HiddenFor(m => m.SessionID)
<div>
#Html.LabelFor(m => m.Content)
#Html.EditorFor(m => m.Content)
</div>
<button type="submit">Submit Comment</button>
You'll get this exact behaviour if you haven't correctly linked in the required scripts. Try adding the following at the top of your main view (not the partial):
<script src="~/Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
Obviously make sure to include the correct version of jQuery you have available in your project.
Update
As you already have the scripts there, something else is obviously wrong. First thing I notice is this:
<div id="comments>
Note the missing quotation-mark. As you have UpdateTargetId = "comments", this may be the cause of your problem.
I'm building a profile page that will have a number of sections that relate to a particular model (Tenant) - AboutMe, MyPreferences - those kind of things. Each one of those sections is going to be a partial view, to allow for partial page updates using AJAX.
When I click on an ActionResult in the TenantController I'm able to create a strongly typed view and the model data is passed to the view fine. I can't achieve this with partial views.
I've created a partial view _TenantDetailsPartial:
#model LetLord.Models.Tenant
<div class="row-fluid">
#Html.LabelFor(x => x.UserName) // this displays UserName when not in IF
#Html.DisplayFor(x => x.UserName) // this displays nothing
</div>
I then have a view MyProfile that will render mentioned partial views:
#model LetLord.Models.Tenant
<div class="row-fluid">
<div class="span4 well-border">
#Html.Partial("~/Views/Tenants/_TenantDetailsPartial.cshtml",
new ViewDataDictionary<LetLord.Models.Tenant>())
</div>
</div>
If I wrap the code inside the DIV in _TenantDetailsPartial inside #if(model != null){} nothing gets displayed on the page, so I'm guessing there is an empty model being passed to the view.
How come when I create a strongly typed view from an ActionResult the user in the 'session' gets passed to the view? How can pass the user in the 'session' to a partial view that is not created from an ActionResult? If I'm missing something about the concept, please explain.
You're not actually passing the model to the Partial, you're passing a new ViewDataDictionary<LetLord.Models.Tenant>(). Try this:
#model LetLord.Models.Tenant
<div class="row-fluid">
<div class="span4 well-border">
#Html.Partial("~/Views/Tenants/_TenantDetailsPartial.cshtml", Model)
</div>
</div>
Also, this could make it works:
#{
Html.RenderPartial("your view", your_model, ViewData);
}
or
#{
Html.RenderPartial("your view", your_model);
}
For more information on RenderPartial and similar HTML helpers in MVC see this popular StackOverflow thread
I know question is specific to MVC4. But since we are way past MVC4 and if anyone looking for ASP.NET Core, you can use:
<partial name="_My_Partial" model="Model.MyInfo" />
Three ways to pass model data to partial view (there may be more)
This is view page
Method One Populate at view
#{
PartialViewTestSOl.Models.CountryModel ctry1 = new PartialViewTestSOl.Models.CountryModel();
ctry1.CountryName="India";
ctry1.ID=1;
PartialViewTestSOl.Models.CountryModel ctry2 = new PartialViewTestSOl.Models.CountryModel();
ctry2.CountryName="Africa";
ctry2.ID=2;
List<PartialViewTestSOl.Models.CountryModel> CountryList = new List<PartialViewTestSOl.Models.CountryModel>();
CountryList.Add(ctry1);
CountryList.Add(ctry2);
}
#{
Html.RenderPartial("~/Views/PartialViewTest.cshtml",CountryList );
}
Method Two
Pass Through ViewBag
#{
var country = (List<PartialViewTestSOl.Models.CountryModel>)ViewBag.CountryList;
Html.RenderPartial("~/Views/PartialViewTest.cshtml",country );
}
Method Three
pass through model
#{
Html.RenderPartial("~/Views/PartialViewTest.cshtml",Model.country );
}
I am loving MVC 2. The whole thing just fits the web so well.
There is one piece of functionality, however, that I am unable to coax out of the Html.DisplayFor() function:
<# Page Inherits="ViewPage<IEnumerable<Foo>>">
<% foreach(var item in Model) { %>
<%: Html.DisplayFor(item.BarBaz) %>
<% } %>
I need to be able to use the DisplayTemplate for this value. Is there a way to do this?
Actually, I figured it out. How stupid of me.
This works:
<# Page Inherits="ViewPage<IEnumerable<Foo>>">
<% foreach(var item in Model) { %>
<%: Html.DisplayFor(m => item.BarBaz) %>
<% } %>
However, this will not work correctly for Html.HiddenFor and Html.ValueFor. In particular, Html.HiddenFor(m => item.NullableDecimal) will render as <input name="NullableDecimal" value="0" /> and Html.ValueFor(m => item.NullableDecimal, "0.00##) will render as 0.00##. However, if you apply a [DisplayFormat(DataFormatString = "{0:0.00########}" to your view model, then it will suddenly work. For this reason, you're probably best off using Html.Display, Html.Hidden, and Html.Value extensions, since you're less likely to run into scenarios where things fail when someone makes a non-local change.
You can accomplish it by getting away from the foreach and using a regular for loop:
<% for (int i = 0; i < Model.Count(); i++) { %>
<%: Html.DisplayFor(p=> p.ElementAt(i).BarBaz) %>
<%} %>
Another option would be to create a PartialView that took an Foo object and only displayed the information that you wanted.
<% foreach (var item in Model)
{
Html.RenderPartial("FooBarBazLine", item);
} %>
This is an old question, but i guess that someone can get benefits from my solution:
Aspx view
<%# Page Inherits="ViewPage<IEnumerable<Foo>>" %>
<% foreach (var item in Model) { %>
<%: Html.DisplayFor(m => item) %>
<% } %>
Razor view
#model IEnumerable<Foo>
#foreach (var item in Model)
{
Html.DisplayFor(m => item)
}
Since DisplayFor accepts an implicit typed lambda, we can directly indicate the instance to display in the loop.
Finally, i'm agree with Anders E. Andersen's answer for the template usage
Html.DisplayFor can automatically iterate over collections, displaying a partial view for each element in the collection.
The first thing you need to do is create an actual model class, with the collection being a property of the class.
public class Bar
{
public IEnumerable<Foo> foo { get; set; }
}
Return this class from your controller instead of the raw collection.
Secondly you need a display template for the Foo class. Display templates are partial views that need to be placed in the folder Views/Shared/DisplayTemplates.
Edit: You can have them in your controller subfolder of Views as well if you want to limit the template to a particular controller. See this question for more information.
Here is an example in razor syntax:
#model YourNameSpace.Foo
<p>#Model.BarBaz</p>
Save it as Foo.cshtml in the DisplayTemplates folder given above.
This template is pretty simple because it is based on your example where you are only displaying a string, but if the collection elements where a class with its own properties you could create a more elaborate template.
Now in the original view, you can get rid of the loop entirely and just write
#Html.DisplayFor(m => m.foo)
Notice foo is the name of the property in your new model class that contains the old collection you looped over before.
DisplayFor will automatically know that the foo property is of type (collection of) Foo and pick up the Foo.cshtml template in the DisplayTemplates folder and show it once for each element in foo.
In Razor I am using
#Html.DisplayFor(model => item.CreatedDate)
Just be careful that a DisplayFor on a POST of a form doesnt actually create a field that can be referenced back in the controller. You would need to use an additional HiddenFor if you need to refer to fields in your submitted POST method.