ASP.NET MVC RenderAction re-renders whole page - asp.net-mvc

How do I prevent renderaction from rendering the masterpage and giving it back to me? I only want it to render 1 section, for eg.
The controller
public ActionResult PaymentOptions()
{
return View(settingService.GetPaymentBanks().ToList());
}
The PaymentOptions View:
#model IEnumerable<Econo.Domain.PaymentBank>
<h2>Payments</h2>
<!-- Stuff here -->
The View
<div class="grid_10">
</div>
<div class="grid_14">
#{Html.RenderAction("PaymentOptions", "Administrator");}
</div>
In grid_14, the header, footer and everything else gets rendered. Is there a way to prevent this?

public ActionResult PaymentOptions()
{
return PartialView(settingService.GetPaymentBanks().ToList());
}
In Razor, partial views and full views have the same extension, so you need to explicitly use the PartialViewResult result type to specify a partial view.

This:
return View(settingService.GetPaymentBanks().ToList());
Has to use the overload so you can specify a master:
return View("PaymentOptions", "", settingService.GetPaymentBanks().ToList());

Related

Adding a dropdown list outside or RenderBody call

I have a .NET MVC project with Razor views and I would like to implement search functionality that consists of a dropdown list, a text box and a search button.
The problem is that I would like to implement this search snippet in my _Layout.cshtml file outside of the #RenderBody() call. This means that the search functionality would be accessible on every page (it would be located at the very top right corner).
I'm trying to find out what is a good way of implementing this. I can get it to work but it would involve adding same code (do get dropdown values) to all controllers and actions.
ViewBag.States = new SelectList(db.States, "Id", "Name");
Is there a better way to implement this? It feels very repetitive to do it this way.
You can have a child action method which returns the partial view needed for your header and call this action method in your layout.
Create a view model for the properties needed.
public class AllPageVm
{
public int SelectedItem { set; get; }
public List<SelectListItem> Items { set; get; }
}
Now create an action method in any of your controller. Mark this action method with ChildActionOnly decorator.
public class HomeController : Controller
{
[ChildActionOnly]
public ActionResult HeaderSearch()
{
var vm = new AllPageVm()
{
Items = db.States
.Select(a => new SelectListItem() {Value = a.Id.ToString(),
Text = a.Name})
.ToList()
};
return PartialView(vm);
}
Now in the HeaderSearch.cshtml partial view, you can render whatever markup you want for your search header. Here is a simple example to render the dropdown. You may update this part to include whatever markup you want (Ex : a form tag which has textbox, dropdown and the button etc)
#model AllPageVm
<div>
<label>Select one state</label>
#Html.DropDownListFor(a => a.SelectedItem, Model.Items, "Select")
</div>
Now in your layout, you can call this child action method
<div class="container body-content">
#Html.Action("HeaderSearch", "Home")
#RenderBody()
<hr/>
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
Make sure you are calling PartialView method from the HeaderSearch child action method instead of View method. If you call View method, it will recursively call the same method and you will get a StackOverflow exception

ViewBag missing

I give data to the ViewBag in the IAuthorizationFilter.OnAuthorization process, and it puts for the _Layout.cshtml-in, but when I use a partial view in normal view the data in the ViewBag is null.
This is normal behavior, or I am doing something wrong?
public class MyAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
void IAuthorizationFilter.OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
filterContext.Controller.ViewBag.Name = this.name;
filterContext.Controller.ViewBag.Menus = user.GetMenu(this.role);
}
...
}
The _Layout.cshtml:
<section id="login">
Hello, <span class="username">#ViewBag.Name</span>!
</section>
<nav>
#Html.MenuLink(ViewBag.Menus as List<Entity.Models.MENU>, (string)ViewBag.Name)
</nav>
The view:
#model Web.ViewModels.RegistrationEntryViewModel
#Html.Partial("_RegistrationEntry", Model)
The action:
[MyAuthorize("ADMINISTRATORS")]
[HttpGet]
public ActionResult NewRegistrationEntry()
{
//The viewbag is already null here
...
}
Please stop using ViewBag like that. It is not designed for this. And reason ViewBag is null in controller (I suspect) that these are different ViewBag objects in filter and in controller.
If you need to do repetitive actions in your view, there are better ways to do that. For your menu I would create an action that reads menu information, puts that in a ViewModel (not in a ViewBag) and outputs a partial view. Then in your Layout I'd render that partial action. (Also add some caching on this partial view)

MVC Entity Framework Razor Issue

I have to following code and there's a problem and I can't figure out what's the problem. Well, I have two ideas about the place where the problem may appear but I can't find a solution.
The problem is that my layout is rendered twice.
Layout.cshtml
<div id="container">
<div id="left_side"> #RenderPage("left_side.cshtml") </div>
<div id="center_side"> #RenderBody() </div>
<div id="right_side"> #RenderPage("right_side.cshtml") </div>
</div>
left_side.cshtml
#if (ViewBag.LeftColumnVisible == true)
{
#Html.Action("GetCategories", "Products");
}
GetCategories method from Products controller
public ActionResult GetCategories()
{
List<Categories> categories = db.Categories.ToList();
...
return View();
}
GetCategories.cshtml
#foreach (System.Collections.DictionaryEntry de in ViewBag.LeftColumnContent)
{
<div> #((Ads.Models.Categories)(de.Key)).Name; </div>
}
It enters the get categories and renders the content.
The problem for rendering twice may be at this line
#Html.Action("GetCategories", "Products"); or when it calls View(). If I comment the line, my layout will be rendered only once.
I'd say there are a couple of issues with your code. First of all, if left_side.cshtml/right_side.cshtml are partial views then you want to be using
#Html.RenderPartial("view")
to render them and not #RenderPage - although #RenderPage will work it's better from a readability point of view to understand exactly what the type of view it is you are working with.
Secondly, if your GetCategories view is a partial view you want to be returning a PartialView and not a View i.e.
public ActionResult GetCategories()
{
...
return PartialView();
}

Create reusable form contact component in asp.net mvc

I'm newbie at asp.net mvc, I'm trying to develop a reusable contact form component for asp.net mvc .
I have tryed to do it creating a PartialView with a form, I don't know if this is the better approach, for create a reusable component
My PartialView is
#model MyModel.ContactData
#using (Html.BeginForm("ContactForm", "ContactForm", FormMethod.Post)) {
<fieldset>
<p>
#Html.LabelFor(model => model.MailAddress)
#Html.EditorFor(model => model.MailAddress)
</p>
<p>
#Html.LabelFor(model => model.Message)
#Html.TextAreaFor(model => model.Message)
</p>
<input type="submit" value="Save" />
</fieldset>
}
The problems start with the controller, the controller is a specific controller for only this partialView.
public class ContactFormController : Controller
{
[HttpPost]
public ActionResult ContactForm(ContactData contactData)
{
if (ModelState.IsValid)
{
return PartialView("MessageSend");
}
return PartialView();
}
}
My problem is in case of some of the required fields are empty, in that case the controller returns only the partial view, not returning the partival view inside its parent context. I have tryed calling the PartialView from parent View as #Html.Partial, #Html.RenderAction, #Html.RenderPartial and the same occurs.
How can I return the partial view Inside it's parent Context? I have tried with
return View(ParentViewsName, contactData) but I dislike it because on form submitting it changes the url on address bar from /Contact to /ContactForm/ContactForm.
Perphaps I'm trying to create a reusable component with a wrong approach? It's better to update with ajax only the PartialView? Alternatives?
Thanks
From my understanding, you wish to display status message which is a partial view after user successfully submits the form. I think tempdata will be apt for this kind of situation.
public class ContactFormController : Controller
{
[HttpPost]
public ActionResult ContactForm(ContactData contactData)
{
if (ModelState.IsValid)
{
TempData["success"] = true;
return RedirectToAction("parentpage");
}
return View(contactData);
}
}
In parent page, check whether TempData["success"] is null and display the partial view "MessageSend".
Finally as Sundeep explains I have done this with ajax like this example Partial ASP.NET MVC View submit.
Thanks for your help.

asp.net MVC partial view controller action

I'm very new to web app development and I thought I would start with recent technology and so I'm trying to learn asp.net as-well as the MVC framework at once. This is probably a very simple question for you, MVC professionals.
My question is should a partial view have an associated action, and if so, does this action get invoked whenever a normal page uses RenderPartial() on the partial view?
While you can have an action that returns a partial view, you don't need an action to render a partial view. RenderPartial takes the partial view and renders it, using the given model and view data if supplied, into the current (parent) view.
You might want an action that returns a partial view if you are using AJAX to load/reload part of a page. In that case, returning the full view is not desired since you only want to reload part of the page. In this case you can have the action just return the partial view that corresponds to that section of the page.
Standard mechanism
Making use of partial view within a normal view (no action needed)
...some html...
<% Html.RenderPartial( "Partial", Model.PartialModel ); %>
...more html..
Ajax mechanism
Reloading part of a page via AJAX (note partial is rendered inline in initial page load)
...some html...
<div id="partial">
<% Html.RenderPartial( "Partial", Model.PartialModel ); %>
</div>
...more html...
<script type="text/javascript">
$(function() {
$('#someButton').click( function() {
$.ajax({
url: '/controller/action',
data: ...some data for action...,
dataType: 'html',
success: function(data) {
$('#partial').html(data);
},
...
});
});
});
</script>
Controller for AJAX
public ActionResult Action(...)
{
var model = ...
...
if (Request.IsAjaxRequest())
{
return PartialView( "Partial", model.PartialModel );
}
else
{
return View( model );
}
}
The accepted answer is completely correct, but I want to add that you can load your partial view using jQuery load. Less configuration needed, if you don't want to consider concurrency.
$("#Your-Container").load("/controller/action/id");
I was able to achieve something similar with this logic.
Within the .cshtml
#Html.Action("ActionMethodName", "ControllerName");
Within the controller
[Route("some-action")]
public ActionResult ActionMethodName()
{
var someModel = new SomeModel();
...
return PartialView("SomeView.cshtml", someModel);
}
And that's it.
If you need to pass values from the .cshtml to the action method then that is possible to.
The answer is no. But sometimes you need some controller action behind a partial view. Then you can create an actionMethod wich returns a partial view. This actionMethod can be called within another view:
#Html.Action("StockWarningsPartial", "Stores")
The actionmethod can look like:
public ActionResult StockWarningsPartial()
{
....
return View("StockWarningsPartial", warnings);
}
and the view 'StockWarningsPartial.cshtml' starts with:
#{
Layout = null;
}
to make it not render your surrounding layout again.
public ActionResult GetStateList(int country_id)
{
List<stateDTO> stateList = new List<stateDTO>();
stateList = bll.GetState(country_id);
ViewBag.sList = new SelectList(stateList, "state_id", "State_Name");
return PartialView("DisplayStates");
}

Resources