I've seen how to use Partial Views from within a View and I understand how a model is passed from the View to a Partial View. What I don't grasp is how to include a Partial View inside of _Layout.cshtml so that I can pass it to the Partial View - or, how the Partial View itself can call a Controller Action to create a Model for use.
Specifically, I want to include a Partial View within _Layout.cshtml to display in the header of every page. The Partial View will display a custom setting in the User Profile. I can't think of any way to obtain the Model without making a Controller Action call - but how is this done in/for a Partial View from within _Layout.cshtml?
Is my only option of accessing a Controller Action to build my Partial View's required Model to use a jQuery call? Or is there another way?
The answer is by calling #Html.Action().
It sounds like you're on the right track.
The key is to try to not pass multiple models around, make models complicated, or use the ViewBag needlessly.
Instead, any time you want information on every page, call an action from your _Layout.
For example, you might have a controller called PartialsController or SharedController.
public class PartialsController : Controller
{
[ChildActionOnly]
public ActionResult UserProfilePartial()
{
UserProfileModel model = new UserProfileModel();
return PartialView("_UserProfile", model);
}
}
The ChildActionOnlyAttribute means that users cannot access the action directly. Only your code can call the action. You can also apply the attribute to the controller so that it affects all actions automatically.
Now call the action from your view (_Layout).
#Html.Action("UserProfilePartial", "Partials")
Related
I have several shared razor partial views in my application to show some details of products on different pages. Now i need to change some of links inside partial views depending on what main view rendered that partial.
For example:
If partial view is rendered inside "index.cshtml", one of the links in partial view should be:
site1 called from index.cshtml
and if it's inside "insert.cshtml" then link need to be
other site that's not 1 and it's called from insert.cshtml
something like:
#if (something.parentview = "index.cshtml")
{ site1 called from index.cshtml}
else {
other site that's not 1 and it's called from insert.cshtml
}
Is there a way to do this?
When you call the Shared PartialView you know where are you.
Is far more easy to pass a parameter to your partial at the time of rendering that rely in "detect" inside of which view is rendered. Imagine... you have 3 levels of nesting... things get more complicated. Imagine if you change routing or view names?
You can use the ViewBag to pass the parameter: in your view you can set something to check inside the Partial. Not controller code is needed.
A more robust approach is pass a ViewModel to your Partial, but if the only data you need to pass is just a parameter, the ViewBag is simpler.
I have a view and a partial view. Within the controller action methods, I have a using statement which establishes some back-end threading context, including providing access to a model object for display in the view.
The problem that I'm having is that while the context and the associated model object are available for the main view, they are disposed before the partial view is rendered. This seems to be the case regardless of whether I pass the model object from the view to the partial view, or reference it some other way.
The controller view action method:
public ActionResult Index()
{
using (var context = GetContext()) {
return View(Context.MyModelObject);
}
}
The controller partial view action method:
[ChildActionOnly]
public ActionResult MyPartialView(ModelObject modelObject)
{
return PartialView(modelObject);
}
The view:
#model ModelObject
#Model.Name
#{Html.RenderAction("MyPartialView", "MyController", new {modelObject = #Model});}
The partial view:
#model ModelObject
#foreach(var item in Model.Items) {
<div>#item.Name</div>
}
If I comment out the RenderAction line of the view, the view displays just fine, accessing the property of the model because the context has not yet been disposed at the end of the using.
However, if I leave it in with the intent of the partial view being rendered, the context has been disposed of, leaving my model object no longer accessible. I would think the using in the main view controller method would not be finished until the view and all its partial views are rendered, but that doesn't seem to be the case. Are partial views deferred to be rendered at some other time? Is there a way around this?
Right now I have a solution which will involve writing a lot of extra code: making a "view model" object which has only the bits of the model object that I need for display in this specific view while it hasn't yet been disposed, then having the view and partial views use that. However, this will be very undesirable as it will result in a lot of duplication between the model and the view models, which will be a subset. It would be very convenient to use the model directly in the view.
The other possibility is that we could alter our backend to dispose of things differently such that they are still available for the partial view whenever it gets around to rendering, but this also seems like a hack.
In summary, is there a better way to do this in the view/controller? Am I making some erroneous assumptions?
MVC was designed with Unit testability in mind. As such, it doesn't render the view when you call View(), it just creates a structure which gets rendered after it returns from the controller.
This design makes it easier to unit test controllers because it doesn't actually require an active web server connection to execute the controller logic.
But, this also means that since you have a using statement in your controller, the view is not actually rendered until after you have returned from the function, and thus the using has called delete on the data context. Thus, your queries will not execute.
You get around this by executing the query within the controller, such as calling .ToList() on the object. You still have to be careful not to execute any lazy operations after returning.
However, a better approach is to not pass your data objects directly to the view, but instead use a view model which you populate from the returned data objects.
Try this
#Html.Partial("MyPartialView", Model)
I'm new to MVC, and I'm implementing a web app with lot of AJAX and partial views.
I have 2 views: 1 base view and 1 partial view. Each view has its own controller. The base view send data to the partial view via Model.
I'd like to make the partial view/controller send data to the base view/controller. What is the best way to do that? Is there a way to refresh the base view from a partial view action?
public ActionResult SendDataToBaseView()
{
return View("BaseView", viewModel);
}
It's not quite clear what your setup is.
If you're updating HTML that was rendered from the main view, then you'll likely have another controller action on the same controller on which you called an action to render the base view. This other controller action may return JSON or HTML (as a Partial View perhaps) and it will be your responsibility on the client side to take the result of the AJAX call and populate the sections of the page that were rendered by the base view with this new data.
Here are the steps that I would envisage being taken
Controller action called to render base view. Let's call the controller BaseController and the action Index
Inside the base view a call is made to render a partiaol view, via Html.RenderPartial(), Html.RenderAction() or Html.Action()
Response is sent to client
Event happens on client requiring update to data rendered by base view.
AJAX request is made to BaseController Update action that returns a JsonResult containing data that can be used to updates parts of the response outputted by the base view.
Receive response on client side and update those parts of the DOM.
I'm trying to embed a small view snippet that steps through a model fragment that works fine when I embed it in a single controller and pass it to a view like so;
Controller:
return View(_entities.formTemplate.ToList());
View:
http://www.pastie.org/666366
The thing is that I want to be able to embed this particular select box in more than just this single action / view, from the googling I've been doing this appears that it should go into a shared view, but I'm not clear then on how I could populate the model within that view from the controller? (or maybe I'm completely missing the purpose for shared views?)
In the other MVC framework I'm accustomed to working with there is the concept of a filter where you can call code before or after any action and mod the model as it passes the controller and goes to the view, is such a thing possible in .net mvc?
Any assistance appreciated.
You'll want to use the HtmlHelper method DropDownList() in order to create a input:
<%= Html.DropDownList("id", new SelectList(formBuilder, "ID", "Name")) %>
You probably want to use a ViewUserControl here.
You have a couple of options if you go that route. If it's model data that is easily available, recreate it at the call site of your RenderPartial like so:
<%=Html.RenderPartial("ViewName", new ModelData())%>
If it's data that is dependent on the current model data, then you'll need to pass that data somehow to your partial view.
ASP.Net MVC also has the concept of before/after controller actions. You decorate your controller method with an Attribute that derives from ActionFilterAttribute. In there, you have access to OnActionExecuting and OnActionExecuted.
I have a strongly typed User Control which should show a user's orders on all pages, it's included in a master page. I have an OrdersController which can give me the current orders and is used at other locations.
How do I tell the UserControl in the Master Page that it should get its Data from that specific Controller / Controller Action? I'd like to access the viewdata within the ascx just as I would in a normal View.
Pass model and ViewData as parameters to the RenderPartial method.
It will make model and view data accessible as if you were in the parent view page.
<% Html.RenderPartial ( "../Shared/HRMasterData/DependentPersonDossiers",
ViewData.Model, ViewData ); %>
One way to do this would be to implement a base controller. Move the logic that obtains the orders to the base controller. Override OnActionExecuted in the base controller and check if the result is a ViewResult. If it is, find the orders and add them to the ViewData. In your master, check if the orders are present in the view data and, if so, render them. If not, show an "order data unavailable" message (this latter shouldn't happen, but it's best to be safe). Reuse (call) the code in the base controller in your OrdersController for the action that renders the orders view.