RenderAction needs to behave different depending on containing page - asp.net-mvc

I use RenderAction to render a partial that is used all over my site.
It is a partial where the user can search for an entity. It depends on the Controller / Action that rendered the parent main view what is done once the entity is found.
Lets say I have the controllers:
HireController, FireController with
Action ActOnPerson and
PeopleController with Action FindPerson which renders the partial
FindPerson
The Views are Hire/SearchPerson.aspx and Fire/SearchPerson.aspx
Each View contains the helper:
<%Html.RenderAction("FindPerson ", "People"); %>
The form that posts to HireController/FireController is contained in the partial.
It needs to be this way, because there are actually a couple of steps (form posts) involved in finding a person.
Is there a way to decide inside the partial FindPerson if the form needs to be posted to FireController or HireController? I guess I am looking for something like public properties of WebControls but for RenderAction.

Just add parameter ("PostTo" or "Next") to People.FindPerson Action:
<% Html.RenderAction("FindPerson ", "People", new { next = Url.Action("ActOnPerson", "HireController") }); %>
<!-- or -->
<% Html.RenderAction("FindPerson ", "People", new { nextaction = "ActOnPerson", nextcontroller = "HireController" }); %>
In FindPerson PartialView:
<form method="post" action="<%= ViewData["next"].ToString() %>">
<!-- or -->
<% using (Html.BeginForm(
ViewData["nextaction"].ToString(), ViewData["nextcontroller"].ToString() ) { %>

Related

Form that submits to the same action, with an id

I'm trying to do something that seems very simple: create a form that submits to same URL it was requested from, with an id.
If I didn't care about the id, I could do:
<% using(Html.Form()) { %>
<!-- stuff -->
<% } %>
But since I want the id, I have to use a different overload.
I would like something along the lines of:
<% using(Html.Form(some, args, new {id="myAwesomeForm"})) { %>
<!-- stuff -->
<% } %>
I can't just hardcode the action and controller because the form is used in a couple of different places. Sometimes the URL will have parameters (/items/edit/1, and other times it will not /items/create)
There must be some incredibly simple way of doing this that is going to make me feel like an idiot when I see it. So, what is it?
Clarification: I mean an id on the HTML element, as in <form action="/my/action[/possible arguments]" id="myAwesomeForm"></form>
Use null for the action and controller; they will be filled in from the current action and controller.
<% using (Html.BeginForm( null, null, null, FormMethod.Post, new { id = 3 } )) { %>
<% } %>
Just use the first overload (routeValues As Object)
It will assume the current, Area Name, Controller Name and Action Name parameters. Post is the default form method.
<%
Using Html.BeginForm(New With {.id = 3})
End Using
%>

Reusable components in ASP.NET MVC

I have feature on my website (some UI and associated functionality) that I want to be able to reuse on multiple pages. For the purposes of this question, let's say it's a "Comments" feature.
There is an area in my application for Components and within the area are a controller: /Controllers/CommentController, and two partial views: /Views/Comment/Index.ascx (for listing comments) and /Views/Comment/Create.ascx (for creating comments).
CommentController looks something like this:
public class CommentController : Controller
{
[ChildActionOnly]
public ActionResult Index()
{
return PartialView(GetComments());
}
[HttpGet]
[ChildActionOnly]
public ActionResult Create()
{
return PartialView(); //this is wrong.
}
[HttpPost]
[ChildActionOnly]
public ActionResult Create(FormCollection formValues)
{
SaveComment(formValues);
return RedirectToAction("Index"); //this is wrong too.
}
}
Index Partial View:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<div>
<% foreach (var item in Model) { %>
<div>
<%: item.Comment %>
</div>
<% } %>
<%: Html.ActionLink("Add a Comment", "Create", "Comment", new { area = "Components" }, null) %>
</div>
Create Partial View:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<div>
<% using (Html.BeginForm())
{%>
Enter your comment:
<div>
<input type="text" name="comment" />
</div>
<p>
<input type="submit" value="Create" />
<% //also render a cancel button and redirect to "Index" view %>
</p>
<% } %>
</div>
The Index partial view is included in a view with RenderAction, like so:
<% Html.RenderAction("Index", "Comment", new { area = "Components" }); %>
This code doesn't work because the forms within the partial views submit to actions on the CommentsController that are marked [ChildActionOnly] (this is by design, I don't want the "Components" to be requested independently of a hosting page).
How can I make this "component" approach work, i.e. have a partial view that submits a form to change the state of a component within a page without losing the hosting page itself?
EDIT:
To clarify, the use of [ChildActionOnly] is not my problem here. If I remove the attribute from my action methods, my code only "works" in that it doesn't throw an exception. My "component" still breaks out of its hosting page when its form is submitted (because I'm telling the form to submit to the partial view's URL!).
You are making MVC fight itself by asking a form to target an action that is marked as ChildActionOnly.
My solution to this problem when I was designing a highly reusable wizard framework, was to NOT mark the actions as ChildActionOnly but instead to detect if the request was an ajax one or just a plain vanilla request.
The code for all this is packaged into a base controller class. In your derived controllers, you do something like:
[WizardStep(4, "Illness Details")]
public ActionResult IllnessDetails()
{
return Navigate();
}
Where the Navigate() method of the base controller has decided whether to return the full view or just the partial view, depending on whether it is, or isn't, an ajax request. That way, you can never return the partial view in isolation.
To ascertain if it is an Ajax request, I used a combination of Request.IsAjaxRequest() and TempData. The TempData is needed because my wizard framework implements the PRG pattern out of the box, so I need to persist the fact that the original post was an ajax one.
I guess this is just one solution and it took a bit of trial and error to get it right. But now I live happily ever after developing wizards like I was JK Rowling...
Use Ajax to post the partial.

how to pass parameters to partial view to show db content?

I am getting my content from a database. How can i use partial views to show content on page using that database?
database table: Content
[Id, Content] these are 2 fields
i want to get the content from db using partial views.
How i will pass an id to a partial view and show the content in view page?
You could use Html.RenderAction:
public class MyController
{
[ChildActionOnly]
public ActionResult Foo(int id)
{
var content = GetContentFromDatabase(id);
return Content(content, MediaTypeNames.Text.Html);
}
}
And in your view include the partial:
<%= Html.RenderAction("foo", "mycontroller", new { id = 5 }) %>
Remark: RenderAction is part of the now released ASP.NET MVC 2 RTM. For ASP.NET MVC 1 you may take a look at the Futures assembly containing this extension method.
Inside your view, use the Html.RenderPartial function. There are a few different uses:
You can pass in a model to the partial view: <% Html.RenderPartial("partialName", model); %>
Or you can pass in a whole new ViewDataDictionary: <% Html.RenderPartial("partialName", viewData); %>
For the full documentation, see here.
EDIT: (Answer to comment):
I would include that data as part of you're view's model. For example, let's say in your model you have:
List<Person> People;
In your view, you want to loop through each one of these, and use a PartialView to display the details:
<% foreach( var p in Model.People){ %>
<p> <% Html.RenderPartial("personPartial", p); %> </p>
<%}%>
Now, your PartialView might look like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Person>" %>
<%=Model.PersonName%>

asp.net mvc parameter from page to a partial view

I'm with a problem, I have a ajax link that pass a parameter, but, the page that it opens does not need that parameter. The page only load 2 partial views, one of those need that parameter passed to the page to load the data correctly, and the other just need to load a form, so, don't need that parameter. How can i acheive this?
In order to do what you want, you will need to add the id to the ViewData construct.
var sysfunctions= UnisegurancaService.FunctionsRepository.All();
ViewData["NeededID"] = id
return View(sysfunctions);
then in your view where you render the partial
<%= Html.RenderPartial("GridFunction", (int)ViewData["NeededID"]) %>
Cast as required of course.
Whatever gets pushed in as the second param becomes the .Model in the partial. I would suggest also strongly typing your partials.
Try this:
<% Html.RenderPartial("GridFunction", new ViewDataDictionary {{"Id", ViewData["Id"]}}); %>
UPDATED:
And add this in your controller action:
ViewData["Id"] = Id;
UPDATED:
And in your GridFunction partial View you can access Id as:
<%= ViewData["Id"] %>
//Controller
public ActionResult EditFunctions(int id)
{
var sysfunctions= UnisegurancaService.FunctionsRepository.All();
return View(sysfunctions);
}
// This is the controller (it does no need the parameter "ID")
//This is the view "EditFunctions"
<div id="formFunction">
<% Html.RenderPartial("FormFunction"); %>
</div>
<div id="gridFunction">
<% Html.RenderPartial("GridFunction"); %> // The grid needs the ID to work correctly but its in the parent page not in the partial call....and the call is an ajax call
</div>
If some dependency of the page needs the parameter, then the page needs to know enough to pass the data in, so the page should be able to provide the data. Or, more simply, just add the parameter to the Page's viewdata and be done with it.

How do I pass a string to a partial view in ASP.NET MVC?

I have a search page that if there is results in the list it passes this list to a view.
However if there are no results I want to send the searched text to a no results found view.
How would I go about this?
You will need to have the searched text available as part of the model that is returned to the view. Then you have two options -
Using the RenderPartial will pass the returned view to the partial view so you can access the value you want from there.
Html.RenderPartial("PartialView");
Alternatively, you can pass the string as the model for the partial view using
Html.RenderPartial("PartialView", Model.SearchedText);
Which might make sense if you want to use the no results partial view with different models.
<%Html.RenderPartial("SimpleTrustGridViewer", ViewData["departmentGrid"]); %>
this passes an object ViewData["departmentGrid"] (this comes from viewdata of the non-partial view) to the partial view SimpleTrustGridViewer.
simplified:
<%Html.RenderPartial("myUserControl", myString); %>
And your partial view inherits like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<string>" %>
Then, in your partial view 'Model' will be the passed string.
The ViewDataDictionary passed from the controller to the view will be the same passed from the View to the Partial View. So if the string you want to pass is in the ViewDataDictionary you don't have to pass it.
<%=Html.RenderPartial("NorResultFound")) %>
But you can use the same view whether there were results or not:
<%if (Model.ResultCount!=0){ %>
<%foreach(var result in Model){ %>
<%= // display results %>
<%}}%>
<%else {%>
<p>There is no results for <%=ViewData["keyword"]%> </p>
<%} %>
I tried this and couldn't get it to work. Say I have
<div id="SearchBar">
<% using (Html.BeginForm("IndexNoJavaScript", "Home"))
{%>
<%= Html.TextBox("SearchTextBox", ViewData["SearchText"]) %>
<input type="submit" value="Search" /> <% } %>
</div>
<% Html.RenderPartial("SearchResults"); %>
And when I try to display the search text in this view like so:
<%= Html.TextBox("SearchedText", ViewData["SearchText"] ) %>
My text box is blank.
You can use jquery and load() action on div tag , insted of using partial; the result is similar.
The load() ajax method call on controller with the text that you want.
like:
$('#divId').load('url/'+ serch content );
Partial view unless you pass to it something else explicitly, has the same Model as parent view.
Two ways (you are talking about views, not partial views right?)
1) in your controller just call a different view in case of no results passing a string as model
2) create a model containing a search status (found x items, no match found, etc...) and a list of results to the same view, allowing the view to render the different results with a switch statement.

Resources