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

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!

Related

In MVC architecture, can a controller and model manage more than one View?

Can I create 2 views for a model and controller?
My current application is MVC complaint , and it has a single view.
I need to create a second GUI, that fetches few information from the model (updated from the first GUI data) , update it and display back in the first GUI.
You can have a different view per action. Based on your description, this seems to be what you are looking for. You have different actions for the same model, it's ok.
You can add a new action for the new information that you want to update and click on the right button of the mouse and click "add view". It will add a new view for that action.
The most common way to do this is to create other actions, one for each View you want to display.
You can have as many Views as you like, as long as you can route between them.
As default, the line return View(); or return View(model) will look for a view in this path: /Views/{ControllerName}/{ActionName}.
You can also specify the view name, as Controller.View() also accepts a string as the view name.
Knowing this, you could display different views from a single action, according to parameters passed to your action.
Example:
public ActionResult Example(bool a)
{
if (a) return View("a");
else return View("b");
}
this will call the view /Views/{ControllerName}/a.cshtml if a is true and /Views/{ControllerName}/b.cshtml if a is false.
You can also call other partial views or actions from your first view, using html helpers: #Html.Partial({ViewName}), #{Html.RenderPartial({ViewName});} or #{Html.RenderAction({ActionName});}
EDIT:
View() also searchs for /Views/Shared/{ActionName}

how to receive input data from muiltiple <form> to a single action?

In my MVC Razor view I have a partial view with <form> tag in it. I need to add another partial view in main view. As <form> is in 1st partial, I m not able to get input data from 2nd partial in action. Can you please suggest how I can get input data from 2nd partial view to action without client side manuplation (Java Script/ JQuery usage) ?
That will be the natural issue with the setup you have. Consider first not putting any form in the first partial, and keep the forms only within the main view. Then render the partials in the main view within the form... a push in the direction of a web forms setup, but it would work...
It's very easy for me to say this, but without seeing your code, I can't provide anything concrete.

PartialView ViewBag data not available in the parent View when using Html.Action()

Seems like a simple issue but I'm obviously missing something.
I have a ViewBag that I created in a partialView.
The PartialView is being rendered by going through
#Html.Action()
In fact that's the ActionMethod inside of which ViewBag variables are being set.
Once set they're available inside of the partial View, however when we come back to the parent where Html.Action() is being called from ViewBag variables are not longer available.
Any idea how come ? How can I access the ViewBag variables that were assigned inside of the Html.Action() action method ?
P.S.
I saw the following question:
Can't access ViewBag in a partial view in ASP.NET MVC3
...From that I gathered that ViewBag variables are passed when you simply render a partial view ( #Html.Partial() ) but they're not when you render a partial view though another Action Method.
Help please ?
According to this SO post Does a child action share the same ViewBag with its "parents" action?, a child action's ViewData/ViewBag is not accessible from its parent action. This sort of makes sense since information stored in ViewData/ViewBag does not survive redirects, and internally the child action is probably redirecting back to the parent action after it finishes executing. You want to store your data in a location that can survive a single redirect, so try using TempData instead and see if it works.

Could somebody explain ASP.NET MVC to me?

I'm trying to get into MVC and currently reading the wrox professional ASP.NET MVC book.
I kind of get it so far. Instead of each URL going to a page it goes to a controller. The controller action then gets the data and decides what view to use.
I also understand that if I have a url like/product.aspx?id=100 then the controller would get the product details and merge them with the "show product" view.
Now here's the bit I don't get...
If my product page has other stuff on it, like a login box, a "top 10 products" section, list of categories etc. which may or not be used on other pages too then how would I include them and keep their code separate?
In the classic aspx model it would be simple. If my top 10 products appeared on every page then I would put it in a master page, but more likely I would make it into a user control if it was going to be used on some pages not others.
From what I understand of MVC so far, my products controller would have to get the top 10 products and so would any other controller that was producing a page with the top 10 products on it.
Confused. Please help.
From what I understand of MVC so far,
my products controller would have to
get the top 10 products and so would
any other controller that was
producing a page with the top 10
products on it.
Not necessarily. You can use Master pages with MVC, as well as Partials to compartmentalize re-usable view content.
This is a good article on using Partials.
http://jeffreypalermo.com/blog/asp-net-mvc-and-the-templated-partial-view-death-to-ascx/
Also, in your Top 10 products example, you could have that rendered by a child action:
[ChildActionOnly]
public ActionResult GetTopTenProducts()
{
var products = db.GetTopProducts(10);
return View(products);
}
You would then have a partial view (.ascx) called "GetTopProducts.ascx" that would be rendered when you call the GetTopTenProducts() action. Then in your Master page, or anywhere you wanted that Top 10 list to show up, you would call it like this:
<% Html.RenderAction("GetTopTenProducts") %>
You're close.
You're just forgetting that your controller is a class that can inherit from a base class.
You can create a base controller class that handles retrieving the top ten products, and then have any controllers that need that functionality inherit from the base class.
You then create a Master Page that uses a Partial View to render the top ten products passed to the View (from the base controller).
...and voila! No code repetition.
Please don't forget that in ASP.NET MVC you still can use MasterPage. With specific to ASP.NET MVC 2 you can display those 10 products using RenderAction which can render Action from any Controller you select.
In addition to that, you should get to know PartialView as well.
You can use master pages and in MVC partial views are synonymous with user controls. The difference being master page does not have a corresponding controller. You an solve with one of two ways.
When you use a partial view you can
pass a model in.
<%= Html.RenderPartial("PartialView",Model) %>
You can just do the work in the partial view, utilizing the code brackets <% %>.

Do I need to have a View Page for every Action in ASP.NET MVC?

I have a customer index page that displays customer lists. I have a search functionality within this page and I want the url to be http://mysite/search?id=434 when i perform the search. The index page will also display the search result.
Thanks
public class CustomerController : Controller
...
public ActionResult Search(int id)
{
ViewData["SearchResult"] = MySearchBLL.GetSearchResults(id);
return View("Index");
}
...
Hope this helps
No, you shouldn't have. Just use View("ViewName"); in the controller to show the appropriate view in other actions.
In the URL that you suggest, you should have a Controller method called 'search' and using the 'index' view for that controller.
If thats the case, you can post it back to the same action and in the Controller have different sets of code for the 'GET' and 'POST' to give the functionality that you are looking for.
Have the HTML form post to the same action that rendered it. That action can decide if it's a non-search (first visit) or a search results rendering. That action can populate ViewData with the appropriate data. That is, if you want to do that.
You can also have two views, really easily. And the action can transparently decide which one to render.

Categories

Resources