MVC Moving from one Model View to Another Model View - asp.net-mvc

I am trying to move from one Model's view to another Model's view. I have a Person model and a BurnProject model. From my Person's Index view I have a "Select" link in which I would like for it to go the BurnProject's Index view. I have tried a couple of things neither have worked.
public ActionResult BurnProject()
{
//return View("~/Views/BurnProject.cshtml");
return RedirectToAction("Index", BurnProject);
}

From my Person's Index view I have a "Select" link in which I would
like for it to go the BurnProject's Index view
Why not create a link which navigates to the index action method of BurnProjectsController ?
So in your Person's index view, you may use the Html.ActionLink helper method.
#model Person
<h1>This is persons index view<h1>
#Html.ActionLink("Select","Index","BurnProjects")
This will generate html markup for an anchor tag which has href attribute set to "BurnProjects/Index".
If you want to pass some data from the person's index view to your BurnProject index action, you can use another overload of Html.ActionLink
#model Person
#Html.ActionLink("Select","Index","BurnProjects",new {#id=Model.Id},null)
Assuming your Person entity has an Id property(which you want to pass the value for) and your BurnProjects index action accepts an id param
public ActionResult Index(int id)
{
// return something.
}

Related

ChildActionOnly attribute not working [duplicate]

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

Partial View different model

I am trying to use a partial view that uses a different model than the one used in the main view. The partial view has
to show a list with the products recently added. But I am stuck on how and where to implement the logic for retrieving the data I need from the database.
Home/Index.cshtml:
#Html.Partial("~/Views/Shared/_LatestProducts.cshtml", new List<Website.Models.LatestProductsList>())
Shared/_LatestProducts.cshtml:
#model List<Website.Models.LatestProductsList>
#foreach (var item in Model)
{
<a href="#" title="img">
<img src="~/Content/images/latest-product-img.jpg" alt="" /><p>#item.ProductName</p>
</a>
}
And I have the following code that I am trying to use in order to get some products for tests and show them in the partial view:
public PartialViewResult _LatestProducts()
{
List<LatestProductsList> latestProd = (from p in db.Products
where p.ID < 5
select new LatestProductsList { ProductName = p.Title }).ToList();
return PartialView(latestProd);
}
I thought that I might use it in the HomeController, but that obviously doesn't work and I am not sure if partial views should have their own controller, if I can
just call it from another class. I am still wrapping my head around ASP MVC, so any help will be appreciate it.
Just call the action that renders the partial view in Index.cshtml.
#Html.Action("_LatestProducts", "Product")
Second parameter is the name of the controller that has the _LatestProducts method.
Just a reminder: Names with _ prefix is for partial views only, not action methods. You should rename it to LatestProducts.

Where to put controller-wide accessible objects

I would like give access to the (currently logged-in) user object to all controllers, and views, in my application. For example, I want to put the users name in my "sidebar" partial, but don't know how to access the user object since that is stored in an other controller. Thanks in advance.
You could use the Html.Action helper method. You could define a view model which will contain all the necessary information you would like to show about the currently logged in user (like his username for example) and then have a controller action which will use the User property of the controller to populate this view model and pass it to a corresponding partial view. Then inside your master page you would include this information using the Html.Action helper:
<div id="sidebar">
#Html.Action("Index", "Users")
</div>
which will invoke the Index action of the UsersController:
public class UsersController
{
public ActionResult Index()
{
UserViewModel model = ...
return PartialView(model);
}
}

Getting actionlink parameter out of route path

I'm trying to add a webform that allows the user to add a database entry with a specific foreign key.
I'm creating the link like this
<%= Html.ActionLink("Edit", "EditSub", new { id = id }) %>
and the resulting URL is http://localhost:3015/TumourGroup/CreateSub/2 (where 2 is the id I passed to the actionlink earlier). The question is, how do I retrieve the value of id from the URL? I'm using it to grab the "main" table so that I can create a new table entry that has a foreign key pointing to the "main" table.
Assuming that TumourGroup is the name of a controller, and you have a route that looks something like this:
routes.MapRoute(
"Default",
"{controller}, {action}, {id}",
new { controller="Home", action="Index", id="" }
)
Then in your TumourGroup controller, you just need a controller method that looks like this:
public ActionResult CreateSub (int id)
{
// blah
}
The parameter id will contain your id from the Url.
EDIT: To include the id when you are submitting a form:
public ActionResult CreateSub (TumourGroupSubcategory tumourSubgroupToCreate)
{
// blah
}
Add the id as a property to your TumorGroupSubcategory class.
In the form view you are submitting, include a hidden field that is named the same as the id in your TumorGroupSubcategory class, and populate it with your id field.
When your user submits the form, the Model Binder will pick up the field, and put it into the id property of tumourSubgroupToCreate automatically.
Have your controller function CreateSub take in int id
public ActionResult CreateSub (int id)
If you want to go to the form with this id, then post with a different set of data, you'd need two functions, differentiated by
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CreateSub (int id)
The get is for navigating to your entry form, the post is called when the form posts.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateSub (TumourGroupSubcategory tumourSubgroupToCreate)
BELOW IS RESPONDING TO CLARIFICATION IN COMMENTS:
Well, if you forego the strongly typed view, you can just do
ViewData["id"] = id;
ViewData["subGroupToCreate"] = ...
Alternatively you can do it in the second form on the client side with Javascript or Jquery

ASP.NET MVC: Accessing ModelMetadata for items in a collection

I'm trying to write an auto-scaffolder for Index views. I'd like to be able to pass in a collection of models or view-models (e.g., IEnumerable<MyViewModel>) and get back an HTML table that uses the DisplayName attribute for the headings (th elements) and Html.Display(propertyName) for the cells (td elements). Each row should correspond to one item in the collection.
When I'm only displaying a single record, as in a Details view, I use ViewData.ModelMetadata.Properties to obtain the list of properties for a given model. But what happens when the model I pass to the view is a collection of model or view-model objects and not a model or view-model itself?
How do I obtain the ModelMetadata for a particular item in a collection?
A simple extension method might do the job:
public static class MyExtensions
{
public static ModelMetadata GetMetadata<TModel>(this TModel model)
{
return ModelMetadataProviders.Current.GetMetadataForType(null, typeof(TModel));
}
}
And in your view:
<%# Page
Language="C#"
Inherits="System.Web.Mvc.ViewPage<System.Collections.Generic.IEnumerable<MyViewModel>>" %>
<%-- Get metadata for the first item in the model collection --%>
<%= Html.Encode(Model.ElementAt(0).GetMetadata().ModelType) %>

Resources