Null Object Exception in MVC Partial View - c#

I have a partial view called _News that when called by itself works as expected.
When I call it from another view using the following code:
<div>
#html.Partial("_News");
</div>
It throws this error:
Object reference not set to an instance of an object
At this line of code in the view:
#foreach (var item in Model) {
Where the view is referencing the model. I realise this means that the view is not being passed the model from the Controller but I am perplexed as to why.
The Controller is called NewsController and is located in Controllers. The View is called _News and is located in Shared Views. The view calling the partial view is the default home/index page.

If your partial needs to access data from the model, you need to pass the model into the Partial() method:
#Html.Partial("_News", Model)
MSDN: http://msdn.microsoft.com/en-us/library/system.web.mvc.html.partialextensions.partial%28v=vs.108%29.aspx
EDIT:
Per your comment below, I think you're actually after this: http://haacked.com/archive/2009/11/17/aspnetmvc2-render-action.aspx - this lets you call a controller action and render the result into the current view.

Could your partial model be a subset or a property of your main views' model? I say could because, to Tieson's point, you can deal with almost any discrepancy between the model the partial wants and the model the view wants... BUT if the model your partial wants is so far disparate from the model your view wants then I will often take that as a possible smell that my two models are not flushed out thoroughly/correctly (basically: "Am I trying to represent too many things or unrelated things on the same page?") .
Additionally, if you can make the model of your partial be a property of the main view's model such that you can pass the model into the partial like this:
#Html.Partial("_News", Model.SomePropertyThatFulfillsTheDataSourceOfThePartial)
then if and when you need to submit the form, this would make model binding much easier as well.

Related

What does the controller return views as, and what does it do with the model?

When I render partial views from the controller, are they purely just HTML strings that get appended to a DOM object?
Controller: return PartialView("~/Areas/Configurations/Views/Supplier/Vouchers/_CardVoucherDetails.cshtml", model);
Client:$("#myDiv").html(theReturnedView);
And when the partial view is returned with a model from the controller, is the model just added as a session or view state and then referenced by the partial view? (because I don't need to handle that at all when rendering the HTML partial view.)
Partial View: #model Model Is this just view state?
ASP.NET MVC is stateless which means that there is nothing like View State by default (specific for Web Forms). Partial views (views in general) are transformed by Razor Engine (or aspx Engine, but I guess you use Razor) to the C# classes, which have 'Execute' method where is html content created. Here is interesting article which presents how Razor works: http://www.c-sharpcorner.com/UploadFile/17e8f6/razor-engine-working-with-views-in-mvc4758/

MVC Partial view to Display list

I have an Action result that returns a list
public ActionResult GetData(Profiles profiles)
{
Vertical Vdata = new Vertical();
List<Ver> Vertical = new List<Ver>();
//Code to fill list
return View(Vertical);
}
And then a partial view to display the List
#model IEnumerable< List<VerticalContainer.Models.Vertical>>
#foreach(var item in Model)
{
<span>#item.name</span>
}
I'm not sure how to render the partial view from my main view
#Html.Action("GetData")??
What do I pass with the Html.Action? or Should I use Partial/RenderPartial?
1- the correct way to render actions is as per the following:
#Html.RenderAction("ACTION_NAME","CONTROLLER_NAME")
where you replace both action name and controller name with the correct values according to your solution.
2- For the passed model, if this action is being rendered inside a view that has a Model property of Profiles
, then you don't have to specify the model to be passed to the action, as it will implicitly read it from the parent view.
if this is not the case, then you will need to store your Profiles values inside a medium variable (for example inside a ViewBag property) and then you will pass it when calling the action, so it should work on this passed model istead of working on the parent view one.
example: #Html.RenderAction("ACTION_NAME","CONTROLLER_NAME", YOUR_MODEL_VALUE_HERE)
Suggestion: if this parital view will just render the list passed, you can skip creating the mentioned action, and just make a call which can render the partial view, passing to it the correct list so it can work with.
To make it more clear, using your question I can see that the action named GetData is just constructing the list called Vertical from the Profiles model passed, so you can construct this list in your original action (Index, Details, WHAT_EVER_THE_NAME_IS) and store it in a ViewBag, then you can call RenderParial instead of RenderAction and this should result in the same output as your mentioned scenario.
example: #{ Html.Partial("ViewName", YOUR_MODEL_HERE);}
#{Html.RenderAction("actionName","controllerName");}
From your main view, you may simply render your Partial view as:
#Html.Partial("_PartialViewName", VerticalList);
VerticalList in this case will be the list of type VerticalContainer.Models.Vertical, that you populated in controller action.

Should I write action methods of the partial view in the controller of the parent view?

After I render a partial view in the view, I wonder what the controller of the partial view is for now?
I don't need it anymore?
We can decide this on the basis of their functionality.
As if your partial view is only meant to be used in your current parent view or it has relevant functionality to the parent view, so in this case we don't need to add a new controller for the partial view.
But, if your partial view is going to be used by some other parent views also or it has some common functionality between other controllers also, then we need put this partial in separate controller.
#Taichi, this is what i think, decision will be always yours.
Partial Views shouldn't have separate controllers. you should place partial view in parents view folder.

Passing correct model to partial view

I have been looking at this error for quite some time, and can't seem to figure out what I might have done wrong.
I have a partial view which is added like this:
<% Html.RenderPartial("~/Views/ForumPosts/ForumPostCreateForm.ascx", ViewData.Model); %>
And the top of the partial view looks like this:
<%# Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl<xxxx.Web.Controllers.ForumThreadsController.ForumThreadFormViewModel>" %>
The error I receive is the following:
The model item passed into the dictionary is of type 'xxx.Core.ForumThread', but this dictionary requires a model item of type 'xxx.Web.Controllers.ForumThreadsController+ForumThreadFormViewModel'.
If am not mistaken both takes the model called ForumThread, but apparently I must have missed something.
You must need to insure about what you are going to pass model into your partial view ,
try to pass a new object of model into partial view
If am not mistaken both takes the
model called ForumThread...
According to the code you posted, the partial view takes a xxxx.Web.Controllers.ForumThreadsController.ForumThreadFormViewModel. Either change the top of your partial view, or find some way to pass a ForumThreadFormViewModel along on a ForumThread object.
Another solution would be to use RenderAction to allow an action to generate the ForumThreadFormViewModel you want.
Please, make sure that your Model is of type xxxx.Web.Controllers.ForumThreadsController.ForumThreadFormViewModel
To check this, look at the point in your controller where its returning the View.
The object that you are putting into the method should be of type ForumThreadFormViewModel

Re-using a partial view (ascx) across different Controllers and Views

Let's assume I have 2 Controllers, TopicsController and PostsController.
For each controller, I have a couple of views (Index & Details).
The Topic (Index) view inherits System.Web.Mvc.ViewPage<IEnumerable<MessageBoard.Models.Topic>>
The Topic (Details) view inherits System.Web.Mvc.ViewPage<MessageBoard.Models.TopicFormViewModel>
I'm using a TopicFormViewModel because I'm sending additional data along with the Model.
The Post (Details) view just inherits System.Web.Mvc.ViewPage<MessageBoard.Models.Post>
Now, I've created a partial view (CreatePost.ascx) which is (obviously :p) used to create a new Post. I want to be able to re-use this control on all of the views you see above.
Update
I've tried rendering the partial view using <% Html.RenderPartial("New"); %> from my Topics/Index.aspx View, but that results in an exception
The model item passed into the dictionary is of type 'System.Data.Linq.Table`1[MessageBoard.Models.Topic]', but this dictionary requires a model item of type 'MessageBoard.Models.Post'.
Now the problem is that my partial view (CreatePost.ascx) accepts a System.Web.Mvc.ViewUserControl<MessageBoard.Models.Post> and I'm not sure how to pass that from all my views above.
I'm also unsure know how to submit the .ascx values to a certain URL (i.e. /Topics/1/CreatePost), how do I tell the submit button to post to that URL?
Thanks in advance,
Marko
Ciao Marko,
Now the problem is that my partial
view (CreatePost.ascx) accepts a
System.Web.Mvc.ViewUserControl
and I'm not sure how to pass that from
all my views above.
I am not sure I understand what do you mean by "how to pass that from all my views above" but I am sure that you dont have to pass an instance of Post from your views. What is going on is that from your views you will invoke a controller action that creates the Post model object and then bind it to the CreatePost.ascx partial.
I'm also unsure know how to submit the
.ascx values to a certain URL (i.e.
/Topics/1/CreatePost), how do I tell
the submit button to post to that URL?
You have two options:
Inside your CreatePost.ascx partial you are probably using a form.
<% using (Html.BeginForm("action", "controller", FormMethod.Post, new {} )) { %>
If you use in the way I am showing you can change the first and the second params respectively to the names of the Action and the Controller that would habndle your submit.
The second option is using jQuery. Simply set an ID for your form and then
$("#myForm").submit(function(event) {
//post an ajax request to the server
});
Hope this helps!
P.S. To be able to reuse your CreatePost.ascx partial place it inside the shared view folder (where your master page is).
In regards to reusing a partial view which is not in the same view folder, use the following and pass in the model required, alternatively you can define a custom route for it.
<% html.RenderPartial("~/Views/<ControllerName>/<PartialViewName>.ascx", <model>);
#Marko
Another way would be to have in the PostController an Action like the following:
[HttpGet]
public ActionResult CreatePost( int topicId ) {
PostModel pm = _manager.CreateDefaultPost();
pm.TopicID = id;
return PartialView( "CreatePost", pm );
}
Then wherever you want to create a Post you can simply call this action that returns the strong-typed view for your new post.
Even if you have a supplementary http call over the network IMO this solution has the advantage to keep the initialization code of a new Post centralized to a single place.
From the View "point-of-view" the call to the action can be done when the user press the "New Post" button and then inject the received markup inside a modal dialog or in a place of your pleasure in the current page.
Hope it helps!

Categories

Resources