mvc.net multiple forms childaction - c#

I have 2 forms on a page, they are included in the masterpage like so:
Html.RenderAction("Form1", "Controller")
and
Html.RenderAction("Form2", "Controller")
The Controller has the following:
<ChildActionOnly()>
Function Form1() As ActionResult
Return View("Form1", New ModelObject())
End Function
<ChildActionOnly()> <AcceptVerbs(HttpVerbs.Post)>
Function Form1(ByVal formCollection As FormCollection) As ActionResult
Return View("Form1", New ModelObject())
End Function
<ChildActionOnly()>
Function Form2() As ActionResult
Return View("Form2", New ModelObject())
End Function
<ChildActionOnly()> <AcceptVerbs(HttpVerbs.Post)>
Function Form2(ByVal formCollection As FormCollection) As ActionResult
Return View("Form2", New ModelObject())
End Function
The forms markup in the ascx is as follows, they are essentially the same form so the markup is very similar:
<% Using Html.BeginForm()%>
<%= Html.TextBoxFor(Function(model) model.Property1, New With {.class = "input"})%>
<input type="submit" class="submitbutton" value="" name="submit" />
<% End Using%>
The problem is, when I submit either form, it runs both post methods.
So Form1 post and Form2 post, yet the values in the form collection are from which ever form was submitted.
My question is:
Why is this submitting both forms with one set of form data?
How can I make it call only the relevant action with the correct form data?
I am sure I am making a simple mistake, just cannot see it for looking.
Project that demonstrates the problem can be found here: TestMVC.zip
Thanks in advance.

I have found a solution to the problem, was wondering if someone would like to comment on the correctness of this "work around".
ok... so step one, Remove the childonlyaction attribute from the post actions and add the controller/action to run when the form is submitted.
Html.BeginForm("Form1", "Form")
This makes sure that the correct post action is called.
The next step was to work out what I wanted to return.
So.. I need to return the custom model if there are validation errors etc. So thought I could do this using meta data or some other custom validation, add the model to TempData and then do a RedirectToAction making the action the page that I came from. i.e. /Home/Index or /Controller/Action
I get the controller/action from the referrer, that should always be set as this is coming from a post action.
Can anyone think of a better way of doing this?? As this is the only way I could find to give the results I want without using Ajax

I see that when you are rendering your forms, you are not naming them explicitly and you are also not mentioning form method. Can you please do something like this:
<% using (Html.BeginForm("ACTION", "CONTROLLER")) {%>
And if you are using child controls then why are you using "Html.RenderAction"? Shouldn't it be "Html.RenderPartial" like:
<% Html.RenderPartial("Search"); %>

If you take [ChildActionOnly] off of your Post actions, it only submits to one action at a time.
So one way to consider it would be to try and find out how to return a partial view as the whole page. Maybe by storing the page's route in a ViewModel around your model, and using RedirectToAction on that route?
This link (http://dotnetslackers.com/articles/aspnet/ASP-NET-MVC-2-0-Using-Multiple-Actions.aspx) seems to suggest that removing ChildActionOnly is all you need to do, but doesn't work in your sample. Most confusing.

Related

ASP.NET MVC post to controller action from same controller

I'm working on this project that currently has the follow method:
[HttpPost]
public ActionResult Service(string identifier)
This function is currently being used by a webpage form
<form method="POST" action="/Connector/Service">
<input type="hidden" id="identifier" name="identifier" value="#TempData["Identifier"]"/>
So Service is used when the user clicks on a button that submits the form on the webpage. The user is taken to this page from another action.
I have to implement a feature where sometimes instead of taking the user to the webpage, the user goes directly to the Service method from the action.
I found this thread when searching: ASP.NET MVC: RedirectToAction with parameters to POST Action
But it seems like that is bad design and returning RedirectToAction with Service actually did not work for me.
return RedirectToAction("Service", new {identifier})
Upon more search it seems like I actually cannot make a post request from my controller. Asp.NET MVC : redirect to another controller with POST Action
Any ideas on what I could do here? I am fairly new to ASP.NET and have no idea what to do at this point. All help is appreciated, thanks.
So turns out I could just call the function directly by doing
Service(identifier)
I kept thinking I had to use RedirectToAction so that didn't even cross my mind.
Thanks Sherlock for the answer!
The tag [post] is used only when a form is submited by the view itself, if your page redirect to a controler function from another view than the one your in, you have two option:
Use the [get] tag, you will probably have more luck with this tag, although i don't know exactly how it work (this might be edited)
Use the tagless function with parameters, if you rediret from another view to a function with a parameter, like public ActionResult Service(string identifier) that has no tag, you will automatically reach this function.
if the parameter haven't been specified, it will simply be NULL.

Basic MVC (button to send e-mail) - ActionLink?

I have a 'mail server configuration' kind of view. On this view are 2 buttons:
[SOME FORM FIELDS]
<input class="button" type="submit" value="#T("Save")" />
<input class="button" type="submit" value="#T("Send Test Email")" />
The first button calls off to my controller and returns the same view with any validation/success messages (this is a form):
[HttpPost]
public ActionResult Index(MailServerSettingsViewModel viewModel)
{
...
That works brilliantly, but obviously the 'Send Test Email' button will do the same.
Assuming I don't want to come away from the page (i.e. load a different view), but want to call off to another controller to send a test e-mail, is the 'proper' way to do this to use the ActionLink helper? From this other controller can I then return this same form view? Or can I somehow use the same controller but determine which button was pressed to decide whether to validate the view model or just call off to another service/class/whatever to send the test e-mail and responding appropriately?
You can probably tell from the way I'm asking this that I come from a WebForms background and it's still a case of me getting used to what's what with MVC.
What I've Tried
For now, I'm actually calling off to this other controller asynchronously with AJAX. It actually works well, and is probably most appropriate, but this won't always be the case so I want to know how I'd achieve the above for other scenarios.
If you don't want ajax you can start a thread to send the email in your controller.
#Html.ActionLink("Send Test Email",
"actionName", "ControllerName",
new { MailServerSettingsViewModel }, new { #class = "button" })
If you set the 'name' attribute on both submit buttons to the same value, you can detect which was clicked in your controller by inspecting the value.

How to prevent ajax form post with regular form post

I have a Razor view that contains a normal form using Html.BeginForm. It also uses Html.RenderAction to insert a partial view that contains another form. I'm using RenderAction so the partial view can be strongly typed with it's own model. That partial view contains an ajax form using Ajax.BeginForm.
The problem I'm having occurs when the regular form in the parent view posts and has validation errors returned from the controller method. The ajax form validates as well and displays its own error messages. At first I thought it was just client-side validation picking up both forms, but when I set a breakpoint, I found that the controller method the ajax form posts to was getting called as well.
I would prefer to keep this view simple and not use ajax for both forms. For the same reason, I would rather not combine the forms into one and use javascript or other methods to differentiate between the two. What are my other options to keep the ajax form from posting or validating when the regular form posts?
My comment to #StephenMuecke finally triggered the right idea for the right keywords to google. And of course, the answer was already on StackOverflow. See Html.RenderAction uses Post instead of Get or How can I get Html.RenderAction to call the Get method on a Post?. #AndrewBarber's answer on the second link was a good answer. After I gave the GET and POST action methods for the ajax form different names and removed the [HttpGet] from the GET action method to allow it be called using either GET or POST, both forms work as expected.

In a C# MVC app is it possible to submit variables from a web page in controls that did not change?

I have a C# MVC application and a <form> in my page.cshtml file. In that form I have <input type="text" ... /> elements. If I submit this form I only get the values in Response.Params or Response.Form from the inputs where I changed the value manually (i.e. Entered the text box then typed something).
If I change the value with jQuery, $('#myInput').val('some value'); this does not count as a change in the input's value and I do not get myInput's value when I submit the form.
Is there any way to make sure all inputs are submitted? If not then is there a good workaround for this, maybe in some event that occurs before my model gets bound? I need to know all the input values from the form when submitted whether they changed or not.
Some additional info:
The form and other values are getting submitted correctly and I am receiving my model when the POST action is called in my controller.
The real issue is when my model is being bound. It is being created and bound with all values except the one not being submitted because it is not in the Request.Params collection.
I have only ever seen this behaviour when a field is disabled. Due to this, I commonly have a javascript function that handles the form submission and re-enables them on submit, this way the correct values get sent to the server.
Something like this does the trick for me (NOTE: I am using JQuery):
$(document).ready() {
$("#ButtonSubmit").click(SubmitForm);
}
function SubmitForm(e) {
e.preventDefault();
//ensure fields are enabled, this example does text and checkbox types
$("[type='text']").attr("disabled", false);
$("[type='checkbox']").attr("disabled", false);
//submit the form
document.forms[0].submit();
}
I am unaware of any easier way to do this, it would be nice if you could 'flag' something that instructs all fields to be submitted. But I don't know if this exists, maybe somebody else can offer a better solution.
EDIT: It appears that disabled fields not submitting is just the nature of HTML, and is not something that is tied to MVC.
It seems that if you make the fields readonly instead of disabled then the values will still submit. However, with this approach you lose the 'disabled' styling. The exception to this rule is select control, it seems this will not submit under readonly either. More information on this can be in this question
Try using the razor helper to build the form tag.
#using(Html.BeginForm()) {
..
// make sure this is a submit button
<input type="submit" value="Save" />
}
In your controller action post method make sure you decorate it [HttpPost].
e.g.,
[HttpPost]
public ActionResult Edit(YourModel model) {
}

See which view contains the form that posted to a controller action

I have a contoller action that a number of forms will post to, all in different views.
Is there a way, in my controller action, to see which view contained the form that posted to it?
I need this to determine to where to redirect the action when the code in the post action is complete.
Thank you!
Two options...you can add a field to your form (or query string) that provides the redirect url. Or you can look at the HttpRequest.UrlReferrer field. It will provide you with the full URL which you have to parse to get the original form.
Hope this helps

Categories