I have several views that have a hidden field like this:
<input type="hidden" runat="server" id="hiddenTab" value="1"/>
each view may have a different value.
I have a base controller that I want to be able to access this value on the constructor:
public class BaseController: Controller
{
public BaseController()
{
string tabid = Request.Form["hiddenTab"];
}
}
and finally I have several controllers that implement this base controller:
public class HomeController: BaseController
{
public ActionResult Index()
{
string tabid = Request.Form["hiddenTab"];
//if tabid = 1, do this.. if it is 2, do this, etc...
}
}
How can I access the hiddenfield value or the value of any other control on the view for that matter when the controller is first loading? The application is just starting at this point, so nothing has been posted yet. I have tried to access the value from both the controller and the base controller and the Request.Form has no values in it.
I am converting an application from aspx to MVC and on the aspx app, the masterpage codebehind had this:
HtmlInputHidden hidddentabid;
hidddentabid = (HtmlInputHidden)Body.FindControl("hiddenTab");
This worked fine for a master page in aspx, but not in MVC. I have spent hours looking and can't find anything on this. All I am able to find is how to access hidden values that are POSTED to a controller. Nothing on when a controller for a view is first rendered.
Any help would be greatly appreciated!
you are missing the name property for the hidden element. you can get the values based on the name. try this
<input type="hidden" id="hiddenTab" name="hiddenTab" value="1"/>
as Andrie mentioned runat="server" is not required in Asp.Net MVC
Under MVC ASP.NET use the Model, reading your code you are not using the paradigm of MVC! The best way to use MVC is to put propriety in your model, reference your model in the view and in post of your action put that model in the argument of action like
[HttpPost]
public ActionResult Index(Modelpage model){...}
the model
public class Modelpage {
public int hiddenTab {get;set;}
}
in the view
[...]
#Html.HiddenFor(m=>m.hiddenTab)
[...]
Add parameter to your action, it will be automatically mapped:
public ActionResult Index(int hiddenTab)
{
//Do smth...
}
runat="server" - this attribute is for classic ASPX pages. You don't need this if you are using ASP.NET MVC View Engine.
html controls having name attribute can only be accessed using request.form object and for this, hidden field or whatever control should be in form.
for accessing any form control in controller action method, firstly check whether the same element is included in form tag or not.
Related
I have set up a menu-controller to drive the top menu links based on which other controller is being used. Each other controller has a separate nested master page for each of its views.
so, i have a menu-controller with several methods that return viewresults, one per each controller, or "section" of the site. So currently each of these methods has its own view to render the menu. but each view to render the menu is the same code, the only thing that changes is the logic in the controller methods based on which links to render.
is there any way to have all of these controller actions target the same view? since the view is the same for all?
thanks
Yes, that is a common practice.
return View("Menu");
Create a strongly typed view that takes a container specifying your menu content. Pass this as a parameter on your return statement.
var thisMenu = CreateMenuForThisRequest();
return View ("Menu", thisMenu);
it depends on what version of ASP MVC you're using; with MVC 2, you can create an ascx control and use RenderAction
in your view you'll put something like
Html.RenderAction("Menu", "Navigation");
and have a navigation controller with a Menu actionresult
public class NavigationController : Controller
{
[ChildActionOnly]
public ActionResult Menu()
{
Menu model;//your menu
return PartialView("YourMenuAscxControlName", model);
}
}
I think if you're using MVC 1, the MVC Future project has the RenderAction but i'm not sure.
For my menu I use the RenderAction method
I'm also using the ActionOutputCacheAttribute from Steve Sanderson
http://blog.stevensanderson.com/2008/10/15/partial-output-caching-in-aspnet-mvc/
you will greatly increase your site loading time with this caching
I have a partial view for ViewBag.count, which is defined in the ShoppingCartController. The problem is that the ViewBag will only show when you are on the ShoppingCart View. I want the ViewBag to be seen on all views. How do I fix this? I am currently rendering the partial like this:
#Html.Partial("_ShoppingCart", new List<bytme.Models.ShoppingCartModel>())
The partial view called _ShoppingCart:
<span class="badge">#ViewBag.count</span>
You should create a seperate action method which returns HTML markup needed to render the cart section of your page and include that in all your view using Html.Action method.
You may also decorate this action method with ChildActionOnly attribute so that users's cannot directly access this action method by requesting the url /ShoppingCart/Cart.
[ChildActionOnly]
public ActionResult Cart()
{
ViewBag.ItemCount = 2; // replace hard coded value with your actual value
return PartialView();
}
and in your partial view (~/Views/Shared/Cart.cshtml), you may write the HTML code which is needed for the cart segment of the page.
<span class="mycart">
Total items in cart #ViewBag.ItemCount
</span>
Here we are using ViewBag to pass the item count numeric value from the action method to it's partial view. But you may use a view model and use the strongly typed view approach to pass data from your action method to the partial view (this is my preferred approach).
Now in other views/layout file where you want to render the cart HTML, you can call the Html.Action method
<div>
#Html.Action("Cart","ShoppingCart")
</div>
<h1>Welcome to my site</h1>
When razor execute your view, it will see this Html.Action method and that will be executed and the output of that (the HTML markup generated fro the action method), will be included in the final output generated for the current view.
I am using the PartialView method, so that it will not try to execute the Layout code. (People make this mistake and gets an infinite calls to the Cart action method.
For Asp.Net Core projects
If you want to do the same thing in asp.net core projects, you may use View components to achieve the same results.
Create a view component to render the cart.
public class CartViewComponent : ViewComponent
{
public IViewComponentResult Invoke(string name)
{
var totalItemCount = 3;
return View(totalItemCount);
}
}
Create a razor view for this view component with the name Default.cshtml inside ~/Views/Shared/Components/Cart directory and you can have your razor code/HTML markup inside that to render the desired HTML. In this example, I am using a strongly typed approach where my view is stongly typed to int type and I am passing an int value from the the Invoke method when calling the View method.
#model int
<span>
Total items : #Model
</span>
Now you can invoke this view component in other views/ layout file by calling the Component.InvokeAsync method.
<div>
#await Component.InvokeAsync("Cart")
</div>
<h1>Welcome to my site</h1>
I want to show a view on some of my forms, which shows a list of alerts, read from a database table. I think I need to use a partial view - but haven't used one.
So far, I created a partial view in my shared views folder called "_Alerts.cshtml".
In that file, at the moment, I simply have:
#{
Layout = null;
}
This is a shared view.
This is just me trying to display something.
And then, on my existing page, on which I want to display the alerts, I have this section of code:
#if (User.Identity.IsAuthenticated)
{
<div class="row">
#Html.Partial("~/Views/Shared/_Alerts.cshtml", null)
</div>
}
This works. However, my understanding is not right. At the moment, I pass no model to it. Is there no controller for the partial view? At the moment, I need to create a controller method - somewhere - that gets me a list of alerts from my data service, and then I want to format that and present it in the partial view. But I am unsure where the controller methods go. If this view is called from 8 different screens, would the 8 controllers for these screens have a call to get my alerts, and format them?
Seems like a lot of duplication.
They need not be duplication.
You can define the action you want inside a controller and call #Html.Action instead of #Html.Partial
Inside you action you can return a partial view.
public class AlertsController : Controller
{
public ActionResult Show()
{
var model = GetModel();//decide where this will come from.
return PartialView("~/Views/Shared/_Alerts.cshtml",model);
}
}
In your layout view or wherever you need to use it. you can simply call it as below.
#Html.Action("Show","Alerts")
If you have all the data you need to pass into the partial, then you can use the #Html.Partial and pass in the model.
If on the other hand, you want the view you are embedding to get the data itself, then you would use Html.RenderAction
When would you use the attribute ChildActionOnly? What is a ChildAction and in what circumstance would you want restrict an action using this attribute?
The ChildActionOnly attribute ensures that an action method can be called only as a child method
from within a view. An action method doesn’t need to have this attribute to be used as a child action, but
we tend to use this attribute to prevent the action methods from being invoked as a result of a user
request.
Having defined an action method, we need to create what will be rendered when the action is
invoked. Child actions are typically associated with partial views, although this is not compulsory.
[ChildActionOnly] allowing restricted access via code in View
State Information implementation for specific page URL.
Example: Payment Page URL (paying only once)
razor syntax allows to call specific actions conditional
With [ChildActionOnly] attribute annotated, an action method can be called only as a child method from within a view. Here is an example for [ChildActionOnly]..
there are two action methods: Index() and MyDateTime() and corresponding Views: Index.cshtml and MyDateTime.cshtml.
this is HomeController.cs
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "This is from Index()";
var model = DateTime.Now;
return View(model);
}
[ChildActionOnly]
public PartialViewResult MyDateTime()
{
ViewBag.Message = "This is from MyDateTime()";
var model = DateTime.Now;
return PartialView(model);
}
}
Here is the view for Index.cshtml.
#model DateTime
#{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<div>
This is the index view for Home : #Model.ToLongTimeString()
</div>
<div>
#Html.Action("MyDateTime") // Calling the partial view: MyDateTime().
</div>
<div>
#ViewBag.Message
</div>
Here is MyDateTime.cshtml partial view.
#model DateTime
<p>
This is the child action result: #Model.ToLongTimeString()
<br />
#ViewBag.Message
</p>
if you run the application and do this request http://localhost:57803/home/mydatetime
The result will be Server Error like so:
This means you can not directly call the partial view. but it can be called via Index() view as in the Index.cshtml
#Html.Action("MyDateTime") // Calling the partial view: MyDateTime().
If you remove [ChildActionOnly] and do the same request http://localhost:57803/home/mydatetime it allows you to get the mydatetime partial view result:
This is the child action result. 12:53:31 PM
This is from MyDateTime()
You would use it if you are using RenderAction in any of your views, usually to render a partial view.
The reason for marking it with [ChildActionOnly] is that you need the controller method to be public so you can call it with RenderAction but you don't want someone to be able to navigate to a URL (e.g. /Controller/SomeChildAction) and see the results of that action directly.
FYI, [ChildActionOnly] is not available in ASP.NET MVC Core.
see some info here
A little late to the party, but...
The other answers do a good job of explaining what effect the [ChildActionOnly] attribute has. However, in most examples, I kept asking myself why I'd create a new action method just to render a partial view, within another view, when you could simply render #Html.Partial("_MyParialView") directly in the view. It seemed like an unnecessary layer. However, as I investigated, I found that one benefit is that the child action can create a different model and pass that to the partial view. The model needed for the partial might not be available in the model of the view in which the partial view is being rendered. Instead of modifying the model structure to get the necessary objects/properties there just to render the partial view, you can call the child action and have the action method take care of creating the model needed for the partial view.
This can come in handy, for example, in _Layout.cshtml. If you have a few properties common to all pages, one way to accomplish this is use a base view model and have all other view models inherit from it. Then, the _Layout can use the base view model and the common properties. The downside (which is subjective) is that all view models must inherit from the base view model to guarantee that those common properties are always available. The alternative is to render #Html.Action in those common places. The action method would create a separate model needed for the partial view common to all pages, which would not impact the model for the "main" view. In this alternative, the _Layout page need not have a model. It follows that all other view models need not inherit from any base view model.
I'm sure there are other reasons to use the [ChildActionOnly] attribute, but this seems like a good one to me, so I thought I'd share.
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.TempValue = "Index Action called at HomeController";
return View();
}
[ChildActionOnly]
public ActionResult ChildAction(string param)
{
ViewBag.Message = "Child Action called. " + param;
return View();
}
}
The code is initially invoking an Index action that in turn returns two Index views and at the View level it calls the ChildAction named “ChildAction”.
#{
ViewBag.Title = "Index";
}
<h2>
Index
</h2>
<!DOCTYPE html>
<html>
<head>
<title>Error</title>
</head>
<body>
<ul>
<li>
#ViewBag.TempValue
</li>
<li>#ViewBag.OnExceptionError</li>
#*<li>#{Html.RenderAction("ChildAction", new { param = "first" });}</li>#**#
#Html.Action("ChildAction", "Home", new { param = "first" })
</ul>
</body>
</html>
Copy and paste the code to see the result .thanks
i'm using the following post type:
<% using (Html.BeginForm())
{ %>
<%= Html.Hidden("EligiblePages", Model.EligiblePages) %>
.... no elements in list appear
$('.btnAction').click(function() {
$.post("Home/AddProduct", $('form').serialize(), function(retval) { $('#addProductDialog').html(retval); });
});
public class ProductViewModel
{
public List<string> EligibleProducts { get; set; }
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult AddProduct(string sender, ProductViewModel model)
{
...
}
i'll update this when i get home and can put together a more precise example.
and in my ViewModel that is getting posted i have a list<string> as a hidden input field. for some reason when the post occurs and i inspect the controller post method that field is not coming over correctly. any ideas?
<%
for(int i=0;i<Model.EligiblePages.Count;i++)
Html.HiddenFor(model=>model.EligiblePages[i]);
%>
This would render hidden input elements and would serealize to your model appropriately when then controller function AddProduct gets called.
Based on your View Model, I would expect your form elements to look like this:
<input type="hidden" name="EligibleProducts[0]" value="whatever" />
<input type="hidden" name="EligibleProducts[1]" value="whatever" />
etc.
That's what the default model binder is expecting.
The DefaultModelBinder will expect one or more form elements to be posted to bind to the List<string> where the name of each form element matches the name of the list property on the ViewModel. Phil Haack wrote a good blog post about various collection binding approaches.
If you have the entire collection rendered in one hidden input as seems to be suggested in your question, then what will be sent to the browser will just be one value to bind to the list and not a collection of values. You may want to enumerate over the collection and render each value in a hidden input. You could also implement your own model binder to dictate how the posted values are bound to the ViewModel, although that is probably overkill in this case.
What do you see being posted for the collection if you use a HTTP debugging proxy tool like fiddler?