How to get current controller and action from inside Child action? - asp.net-mvc

I have a portion of my view that is rendered via RenderAction calling a child action. How can I get the Parent controller and Action from inside this Child Action.
When I use..
#ViewContext.RouteData.Values["action"]
I get back the name of the Child Action but what I need is the Parent/Calling action.
Thanks
BTW I am using MVC 3 with Razor.

And if you want to access this from within the child action itself (rather than the view) you can use
ControllerContext.ParentActionViewContext.RouteData.Values["action"]

Found it...
how-do-i-get-the-routedata-associated-with-the-parent-action-in-a-partial-view
ViewContext.ParentActionViewContext.RouteData.Values["action"]

If the partial is inside another partial, this won't work unless we find the top most parent view content. You can find it with this:
var parentActionViewContext = ViewContext.ParentActionViewContext;
while (parentActionViewContext.ParentActionViewContext != null)
{
parentActionViewContext = parentActionViewContext.ParentActionViewContext;
}

I had the same problem and came up with same solution as Carlos Martinez, except I turned it into an extension:
public static class ViewContextExtension
{
public static ViewContext TopmostParent(this ViewContext context)
{
ViewContext result = context;
while (result.ParentActionViewContext != null)
{
result = result.ParentActionViewContext;
}
return result;
}
}
I hope this will help others who have the same problem.

Use model binding to get the action name, controller name, or any other url values:
routes.MapRoute("City", "{citySlug}", new { controller = "home", action = "city" });
[ChildActionOnly]
public PartialViewResult Navigation(string citySlug)
{
var model = new NavigationModel()
{
IsAuthenticated = _userService.IsAuthenticated(),
Cities = _cityService.GetCities(),
GigsWeBrought = _gigService.GetGigsWeBrought(citySlug),
GigsWeWant = _gigService.GetGigsWeWant(citySlug)
};
return PartialView(model);
}

Related

Trying To pass list of data in from controller to partial view in mvc

I am trying to pass list of data through viewbag from controller to partial view but getting error
in login form after submitting data taking it from formcollection through HttPost and once action complete it return to home page from there i am calling method Page_Init inside that in 'loadmessage' method i am trying to return list to a partial view "Header" based on condition.but not able to perform getting error
Home controller
[HttpPost]
public ActionResult Login(FormCollection form)
{
return View("Home");
}
in Home.cshtml
calling method page_init in controller
$.get("/Home/Page_Init",null, function (data) {
alert(data);
});
Home controller
public ActionResult Page_Init()
{
loadMessages();
return view("Home");
}
public ActionResult loadMessages()
{
List<MessageModel> lstMessages = new List<MessageModel>();
List<MessageModel> lstInfoMessages = new List<MessageModel>();
lstInfoMessages = lstMessages.Where(msg => msg.MESSAGE_TYPE.Equals(CommonConstants.SAFETY_MESSAGE_INFO, StringComparison.InvariantCultureIgnoreCase)).ToList<MessageModel>();
if (lstInfoMessages.Count > 0)
{
ViewBag.lstInfoMessages = 1;
ViewBag.lstInfoMessages1 = lstInfoMessages;
return PartialView("Header", lstInfoMessages);
}
}
also trying to go to partial view from Home view
#ViewBag.lstInfoMessages1
#if (ViewBag.lstInfoMessages == 1)
{
#Html.Partial("Header",ViewBag.lstInfoMessages1)
}
Expected that list of information should go to partial view and bind
Error:Not getting Exact syntax what to do and how to proceed the steps tried above throw error
#Html.Partial method does not accept the dynamic value – so we need to cast it to the actual type.
#model MessageModel //you need to give correct path of MessageModel
#ViewBag.lstInfoMessages1
#if (ViewBag.lstInfoMessages == 1)
{
#Html.Partial("Header", (List<MessageModel>)ViewBag.lstInfoMessages1)
}
In Header Partial view, you can retrieve list using #Model

Render Action from area in layout page of mvc

I want to Render Index() action off my Area (named Menu) in Layout Page of my main MVC project by this code
and got Error on this line of layout
#{Html.RenderAction("Index", "Menu", new { area = "" }); }
Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerAsyncWrapper'.
and this is my AreaRegistration Code just for inform:
public override string AreaName
{
get
{
return "Menu";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Menu_default",
"Menu/{controller}/{action}/{id}",
new { controller = "Menu", action = "Index", id = UrlParameter.Optional },
new string[] { "Menu.Controllers" }
);
}
as you see my controller name is Menu
Edited: the main reason of my problem is this ...Index action off my area cant return his view ...i was set one break point in Index action, and one break point inside of Index view ... and the program is reaching and stop on first one,but never stops in second one!! ...
So
the main problem is this ...Index action of my area doesn't return Index view..
Try this One
#Html.Action("Index", "Menu")
i solve it. actually, only solution to do this thing was using RenderPartial with direct path:
#{ Html.RenderPartial("~/Areas/Menu/Views/Menu/Index.cshtml");}

Two partial views inside an MVC view

I have the following scenario, where I have one model (named Model A) in a view (View1).
This view initially loads a partial view (Partial View 1)
On button click of partial view, I am trying to pass the id generated to another partial view (Partial View 2).
But I am getting an error saying View 1 cannot be found, which loaded without any issues on first run.
If I remove the else statement, the page successfully reloads after submission.
Any tips on passing this model object successfully to the other view please.
I put id=1 and tested it and the same error occured.
I tried RenderAction, RenderPartial and all these failed
Page
#model MyModel
#{
if (ViewBag.Created ==0) {
#Html.Partial("CreateView1",Model);
}
else
{
{ Html.Action("Action2", "Area/Controller2", new { id = Model.Id }); }
}
}
Controller methods:
Controller 1:Entry point of view
[Route("{CreateView1}")]
public ActionResult Create() {
ViewBag.Created = 0;
return View(new MyModel());
}
[Route("{CreateView1}")]
[HttpPost]
public ActionResult Create(MyModel model) {
...........................
ViewBag.Created = 1;
}
Controller 2 which renders 2nd partial view:
public PartialViewResult Index(int createdId)
{
return PartialView(new List<Model2>());
}
Regarding View 1 cannot be found, is because the keyword return in your second Create action is missing. The button click submits the form to the Create method with [HttpPost] attribute and the end of the method, it needs a return View.
Reg Any tips on passing this model object successfully to the other view please, The return in the second Create method should be return View(model); and not 'return View(new MyModel);` as later on in the View you are going to use the Model.
Re I put id=1 and tested it and the same error occured., because runtime never reachs that point as the operation is being handed to '[HttpPost] Create' and it never get back to your Original Page.
There are other issues with your code as you are using different names in your code than what you mention in your description...
A simple solution is:
1- use the following return at the end of you [HttpPost]Create Action:
return RedirectToAction("Action2", "Area/Controller2", new { id = model.Id});
2- replace the following code in your initial page
if (ViewBag.Created ==0) {
#Html.Partial("CreateView1",Model);
}
else
{
{ Html.Action("Action2", "Area/Controller2", new { id = Model.Id }); }
}
with the following:
#Html.Partial("CreateView1",Model);
and remove anywhere you set ViewBag.Created = 0 or ViewBag.Created =1
I also assume the action action2 in controller Controller2 returns a valid Partial View.
Hope this help you get some idea to fix your code.
You may have omitted this for brevity, but you will want to return a viewresult at the end of your post action:
return View(new MyModel());
try this:
if (ViewBag.Created ==0) {
#Html.RenderPartial("CreateView1",Model);
}

MVC3 - RenderPartial inside RenderSection not working

I'm working on an MVC3/Razor page, and in my _layout I have
#RenderSection("relatedBooksContainer", false)
In another page I use that section with:
#section relatedBooksContainer
{
#{ Html.RenderPartial("~/Views/Shared/Bookshelf.cshtml", Model.Books);}
}
This doesn't work. From what I've read, RenderSection will only ever go one layer deep - it has no concept of the Html.RenderPartial in the related section and will just return a blank area. The workaround I read at http://forums.asp.net/t/1590688.aspx/2/10 is to use RenderPage and commit the returned HTML to a string, then outout that string in the render section...which works! That is, until I pass a model to the partial page, then it throws an error saying:
The model item passed into the
dictionary is of type
'TheBookshelf.ViewModels.BookshelfViewModel',
but this dictionary requires a model
item of type
'System.Collections.Generic.List`1[TheBookshelf.EntityModel.Book]'.
Anyone have any idea why this might be happening? Are there any other ways to achieve this?
Try the #Html.Partial instead
#section relatedBooksContainer
{
#{ Html.Partial("~/Views/Shared/Bookshelf.cshtml", Model.Books);}
}
The error message is regarding the type and return type of the Bookshelf from the model.
public IEnumerable<Book> Bookshelf()
{
var q = from book in bookshelf
select book;
IEnumerable<Book> myBooks = q.ToList<Book>();
return myBooks;
}
did the solution in the provided link work for you?
I couldn't get it to work. That is I couldn't get ViewData["MainView"] to pass the data from Layout.cshtml to partialview. This aparently is a feature as every view is supposed to have it own ViewData obj. It seems ViewData is not global like I have thought. So what I get in ViewData["MainView"] from Layout in my partial view is null......I eventually found a work around for this and was able to pass the page reference from Layout to Partialview via a #Html.Action call from Layout -> Controller -> PartialView. I was able to get my partialview to access and write to the correct rendersection. However I want to call the same partialview many times in my Layout.cshtml. A subsequent call to the same Partialview again in the Layout, does not work, as the reference to layout has changed since the first call and rendersection update. So the code looks like this:
Layout.cshtml:
#RenderSection("Top", false)
#Html.Action("Load", "Home", new { viewname = "_testPartialView", pageref = this })
#Html.Action("Load", "Home", new { viewname = "_testPartialView", pageref = this })
Partial View:
#Model Models.testModel
#Model.Content
#{
var md = (System.Web.Mvc.WebViewPage)#Model.pageRef;
#*This check fails in subsequent loads as we get null*#
if(md.IsSectionDefined("Footer")) {
md.RenderSection("Footer");
}
else {
md.DefineSection("Footer", () => { md.WriteLiteral("<div>My Contents</div>"); });
}
}
}
controller:
public ActionResult Load(string viewname, System.Web.Mvc.WebViewPage pageRef)
{
var model = new Models.testModel { Content = new HtmlString("time " + i++.ToString()), pageRef = pageRef };
return PartialView(viewname, model);
}

An easy way to set the active tab using controllers and a usercontrol in ASP.NET MVC?

How do I create tabbed navigation with the "Current" tab highlighted in the UI?
Before MVC I looked at the file path and figured out which tab was currrent. Now it's a lot easier, you can assign the current tab based on the current controller.
Check it out ...
Most of the work happens in the usercontrol.
public partial class AdminNavigation : ViewUserControl
{
/// <summary>
/// This hold a collection of controllers and their respective "tabs." Each Tab should have at least one controller in the collection.
/// </summary>
private readonly IDictionary<Type, string> dict = new Dictionary<Type, string>();
public AdminNavigation()
{
dict.Add(typeof(BrandController), "catalog");
dict.Add(typeof(CatalogController), "catalog");
dict.Add(typeof(GroupController), "catalog");
dict.Add(typeof(ItemController), "catalog");
dict.Add(typeof(ConfigurationController), "configuration");
dict.Add(typeof(CustomerController), "customer");
dict.Add(typeof(DashboardController), "dashboard");
dict.Add(typeof(OrderController), "order");
dict.Add(typeof(WebsiteController), "website");
}
protected string SetClass(string linkToCheck)
{
Type controller = ViewContext.Controller.GetType();
// We need to determine if the linkToCheck is equal to the current controller using dict as a Map
string dictValue;
dict.TryGetValue(controller, out dictValue);
if (dictValue == linkToCheck)
{
return "current";
}
return "";
}
}
Then in your .ascx part of the usercontol call into the SetClass method to check the link against the dict. Like so:
<li class="<%= SetClass("customer") %>"><%= Html.ActionLink<CustomerController>(c=>c.Index(),"Customers",new{#class="nav_customers"}) %></li>
All you need now is the CSS to highlight your current tab. There are a bunch of different ways to do this, but you can get started with some ideas here: http://webdeveloper.econsultant.com/css-menus-navigation-tabs/
Oh, and don't forget to put the usercontrol on your page (or MasterPage) ...
<% Html.RenderPartial("AdminNavigation"); %>
I wrote some simple helper classes to solve this problem. The solution looks att both which controller that is used as well as which action in the controller.
public static string ActiveTab(this HtmlHelper helper, string activeController, string[] activeActions, string cssClass)
{
string currentAction = helper.ViewContext.Controller.
ValueProvider.GetValue("action").RawValue.ToString();
string currentController = helper.ViewContext.Controller.
ValueProvider.GetValue("controller").RawValue.ToString();
string cssClassToUse = currentController == activeController &&
activeActions.Contains(currentAction)
? cssClass
: string.Empty;
return cssClassToUse;
}
You can the call this extension method with:
Html.ActiveTab("Home", new string[] {"Index", "Home"}, "active")
This will return "active" if we are on the HomeController in either the "Index" or the "Home" action. I also added some extra overloads to ActiveTab to make it easier to use, you can read the whole blog post on: http://www.tomasjansson.com/blog/2010/05/asp-net-mvc-helper-for-active-tab-in-tab-menu/
Hope this will help someone.
Regards,
--Tomas
One method I am using on a current project - this also helps for other page-specific CSS needs.
First, an HTML helper that returns a string that represents the current controller and action:
public static string BodyClass(RouteData data) {
return string.Format("{0}-{1}", data.Values["Controller"], data.Values["Action"]).ToLower();
}
Then, add a call to this helper in your master page:
<body class="<%=AppHelper.BodyClass(ViewContext.RouteData) %>">
...
</body>
Now, you can target specific pages with your CSS. To answer your exact question about navigation:
#primaryNavigation a { ... }
.home-index #primaryNavigation a#home { ... }
.home-about #primaryNavigation a#about { ... }
.home-contact #primaryNavigation a#contact { ... }
/* etc. */
MVC's default Site.css comes with a class named 'selectedLink' which should be used for this.
Add the following to your ul list in _Layout.cshtml:
#{
var controller = #HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
}
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home", null, new { #class = controller == "Home" ? "selectedLink" : "" })</li>
...
</ul>
I know this is not clean. But just a quick and dirty way to get things rolling without messing with partial views or any of that sort.

Resources