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 );
}
Related
I've written a system using ASP.NET MVC that generates various financial reports. Each report is in it's own controller, each controller has its own "Report" Action. The Action Renders a partial view with the report in the ViewBag which it passes to javascript on the front end and puts the rendered element in a JQueryUI dialog.
A user may run a Balance Sheet report then another user may run an Income Statement report, after the first user runs the Balance Sheet Report and instead of seeing the Income Statement, the second user sees the Balance Sheet.
This is the code that returns the report as a JSON object
//Initialize report and add datasources etc.
reportViewer.LocalReport.Refresh();
ViewBag.ReportViewer = reportViewer;
return Json(JsonResponse.Success(RenderRazorViewToString("PrintVoucher", null)));
Here is the Partial View
#using ReportViewerForMvc;
<div class="col-md-12 col-lg-12 col-sm-12 col-xs-12">
#Html.ReportViewer(ViewBag.ReportViewer as Microsoft.Reporting.WebForms.ReportViewer)
</div>
Any advice or guidance would be greatly appreciated!
We ran into the same issue and it seems to be related to a concurrency bug in the ReportViewerForMvc. Stumbled on this old github link which had the information and proposed fix. Hope this helps.
https://github.com/nrifath2009/ReportViewerForMvc/pull/1
Try making your partial view a strongly typed view for "reportViewer" using it in the #Html.ReportViewer() and not the view bag.
After that go to the code that returns that partial view and on return set that as
return Json(JsonResponse.Success(RenderRazorViewToString("PrintVoucher", reportViewer)));
Make sure that your Action have no OutputCache attribute to make
sure the server always calculate new report for each request or Set
VaryByParam on attribute constructor
Use strongly type model instead of ViewBag
Initialize new object of the ReportViewer on each call instead of using a single static object.
Use PartialView on Controller action and pass the report object to the PartialView, Razor engine will process the Partial View with the model and generate an HTML markup as a return for the json call.
Here a working Sample of the controller and the View (I've used Bootbox instead of JqueryUI)
Controller :
[HttpPost, ValidateAntiForgeryToken]
public PartialViewResult Report(/*Pass Optional Parameters If Required*/)
{
var reportViewer = new ReportViewer();
//reportViewerInitialization
return PartialView("PrintVoucher", reportViewer);
}
JavaScript Method for loading Report View
function showReport(reportControllerName)
{
var dialog = bootbox.dialog({
message: '<p><i class="fa fa-spin fa-spinner"></i> Loading...</p>'
});
$.ajax({
type: "POST",
url: '/'+ reportControllerName +'/Report/',
data: {/*DataPassed To The Report Action*/},
success: function (data) {
//data Field will contain an Html markup resulted from razor engine process for PrintVoucher PartialView
dialog.find('.bootbox-body').html(data);
}
});
}
PrintVoucher.cshtml
#using ReportViewerForMvc;
<div class="container">
<div class="row">
<div class="col-md-12 col-lg-12 col-sm-12 col-xs-12">
#Html.ReportViewer(Model as Microsoft.Reporting.WebForms.ReportViewer)
</div>
</div>
</div>
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 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.
I have a simple MVC application that retrieves DB Server, database, username and password from the user to store in an XML file. I want to add a "Test Connection" button to the screen and have it execute a method on the controller called TestConnection. The problem is the TestConnection method resets all the information on the screen when clicked since the View is being returned with no model. (because a GET operation is occurring). Here is my code:
From the Controller (named FrameworkConfigurationController.cs)
public ActionResult TestConnection()
{
return View("Index");
}
[HttpPost]
public ActionResult TestConnection(FrameworkConfigurationViewModel viewModel)
{
// TODO: Test will occur here
viewModel.DbConnectionMessage = string.IsNullOrEmpty(viewModel.DatabaseName) ? "Connection unsuccessful" : "Connection successful";
return View("Index", viewModel);
}
From my View (FrameworkConfiguration/Index):
#model Framework.ViewModels.FrameworkConfigurationViewModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>FrameworkConfigurationViewModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ServerName)
</div>
#* Edited for brevity *#
<button type="submit" onclick="location.href='#Url.Action("TestConnection")'">
Test Connection</button>
#Html.ValueFor(model => model.DbConnectionMessage)
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to Dashboard", "Index", "Home")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Admittedly, I am new to MVC programming. I'm coming from a Silverlight/MVVM background so the concept is not foreign to me...the disconnected nature of web programming is. I've followed some tutorials out there, but none of them seem to cover this type of thing - every example is contrived. I know how to do this with webforms and code-behind, but I would like to accomplish this with MVC.
Is there some way to "force" the POST operation instead of GET? I was under the impression that
<button type="submit">
accomplished that. Perhaps the implementation of the onclick I have written isn't correct. I am sure this is HTML 101 stuff, but I can't seem to find a simple answer to this.
Thanks for any help you can offer,
Jason
Why not have the Test Connection button trigger an Ajax action to call the controller, and display the result?
That way you avoid submitting your entire page.
In case you're not familiar with the details, here's a good overview on getting started with Ajax and MVC 4
http://ofps.oreilly.com/titles/9781449320317/ch_AJAX.html
I have a shared view in my _Layout.cshtml for my header named "_Header.cshtml".
I would like to display text and image from the database, so I need my controller to go in the database and return it to the _Header.cshtml.
How can I do that because the controller called is always different each page the user goes. Is there a way to have controller with Shared View?
Here is the _Layout.cshtml
<div id="header">
<div id="title">
#Html.Partial("_Header")
</div>
<div id="logindisplay">
#Html.Partial("_CultureChooser")
<br />
#Html.Partial("_LogOnPartial")
</div>
<div id="menucontainer">
#Html.Partial( "_MenuPartial")
</div>
</div>
<div id="main">
#RenderBody()
<div id="footer">
</div>
</div>
</div>
In your contoller action you could specify the name of the view:
public class MenuController : Controller
{
[ChildActionOnly]
public ActionResult Header()
{
var model = ... // go to the database and fetch a model
return View("~/Views/Shared/_Header.cshtml", model);
}
}
Now in your _Layout.cshtml instead of #Html.Partial("_Header") do this:
#Html.Action("Header", "Menu")
... 1 year later would just like to add one thing to Dimitrov answer. You can make the controller a little cleaner:
public class MenuController : Controller
{
[ChildActionOnly]
public ActionResult Header()
{
var model = ... // go to the database and fetch a model
return Partial("_Header", model);
}
}
Create an action in one of your controllers to render the header view, then simply call #Html.RenderAction("Header") within the _Layout.cshtml.
You can also pass a model into the RenderAction method if required.
While the RenderAction approach that WDuffy provided works well, I recently blogged about this very topic using another approach using IoC:
http://crazorsharp.blogspot.com/2011/03/master-page-model-in-aspnet-mvc-3-using.html
I hope the question you have asked is Like....
Can we have a controller for a Shared Layout View.
Simple answer is No.
To achieve this goal you have to create a partial view for the Same purpose and put it into you shared Layout. By that means you can achieve you Goal