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

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.

Related

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) {
}

Event when form submittion ends

I have this:
<form id="import_form" method="post" enctype="multipart/form-data" action="/Blah/Blah">
<input type="file" id="fileUpload" name="fileUpload"/>
<input type="submit" name="submit" value="Import"/>
</form>
$('#import_form').submit(function () {
...
});
Here is the c# method:
[AcceptVerbs(HttpVerbs.Post)]
public string Blah(HttpPostedFileBase fileUpload, FormCollection form)
{ ... }
I want when Blah finishes executing a javacript code to start executing. How to do this?
The submit event is called before it.
This depends on how the form is being submitted.
If you're submitting the form via AJAX then you can execute some JavaScript in the handler for the response. However, given that there's a submit button, I'm assuming for the moment that you're not doing this via AJAX and are instead posting the whole page to the server and rendering a response.
In this case, to execute some JavaScript after the form post, you're going to need to render that JavaScript in the response from the server as part of the next page. When the server constructs the view, include the JavaScript you want to execute in that view.
Keep in mind the request/response nature of the web. When something on the server executes, the client is unaware of it and disconnected from it. The end result of any server-side processing should be an HTTP response to the client. In the event of submitting a form or clicking a link or anything which results in a page reload, that response is in the form of a new page (view). So anything that you want to do on the client after the server-side processing needs to happen as part of that response.
Edit: I just noticed that Blah is returning a string. Is this even working for you? How does the form submit result in a new view? Or am I unaware of a feature in ASP.NET MVC?
This is what I did in the end.
My form returns the exact same view with whom it was called.
I add a ViewData in the Blah method.
In the view, in the $(function()) event I check if ViewData has a value, I execute the javascript code.

Is using tempdata validate method entry and pass info through multiple POSTs in the controller a bad practice? Alternatives?

First, some context:
In my controllers, I return RedirectToAction's on successful HTTP POSTs. I use TempData to hold onto the user's entered model data so that the method I redirect to can use this input data again.
Example:
1. Enter userID into search field.
2. Click button, POST is performed, user is found in database through my repository, userID stored in TempData, call RedirectToAction("Edit")
TempData["user"] = searchViewModel.userID;
return RedirectToAction("Edit");
perform edits on Edit view, click commit button, user info is stored in TempData, call RedirectToAction("Confirm");
display changes made on the Confirm view, click "Confirm", final HTTP POST is performed and changes are made through my repository service.
This seems to work well. In order to handle people trying to skip ahead to a page in the address bar by typing "../Edit/Confirm" I have this check in my Confirm method:
if (TempData["editUserViewModel"] == null)
return RedirectToActionPermanent("Edit");
Is this the best way to handle address bar input? I also do TempData.Keep("editUserViewModel") so that refreshes work. Is this the best way to handle refreshes?
For going from step 1 to 2, I would suggest a paramaterized action instead:
Enter userID into search field.
Click button, POST is performed, user is found in database through my repository
Call RedirectToAction("Edit", new {UserId = foundUserId})
Also, when searching, you probably shouldn't be doing a POST. A GET is just fine when you are looking for information and not mutating it. This avoids the PRG pattern altogether for the first place where you are using tempdata, since you do a GET instead of a POST.
As for the confirm, there is another way to do this without tempdata. Instead of redirecting to your Confirm action, POST to it, and return your confirm viewmodel. Only after that second POST do you hit the repos and finish out the PRG pattern after the POST with a Redirect and finally a Get.
Users should not be able to do any type of GET for your Confirm action, as can be seen by your bandaid for it. So, just don't allow gets at all. POST from the edit form to the confirm action, return a view, and then POST from that view to a second POST action method. Since these are all part of the same process, you shouldn't have to deal with redirects or tempdata until the process is complete (repos updated).
Update (reply to comments)
1.) If I remove the [HttpPost] attribute on my SearchUser function, how will my search button on the view know what to call?
Your search button is nested within a <form> HTML element. You will need to change the form's method to GET. If the attribute is not present, I believe POST is the default. Your search button will remain the same, but the form will submit the user-enetered input as an HTTP GET request instead of an HTTP POST:
<form method="GET">
...
<input type="submit" value="Search" />
</form>
2.) Can you clarify removing the Redirect to Confirm? I'm having trouble understanding how I would change a Redirect to a POST
It's difficult to explain this to someone just starting with web development, but in essence, every redirect is always an HTTP GET request. This is why you had to put the data into session (tempdata uses session) in order to maintain it across stateless requests.
Basically, here is your workflow:
User enters search input and clicks submit
The search in (1) is sent as a GET request to some action method, which returns a view.
The view returned in (2) contains a <form method="POST" action="/Users/StillNeedsConfirmationAction"> with additional input elements. This is the form that will be used to edit data.
User inputs data in the form view from (3) and clicks submit.
The action method StillNeedsConfirmationAction on your UsersController accepts an HTTP POST with a viewmodel object. Rather than redirecting though, the action simply returns another view, passing the same viewmodel object.
The view returned in (5) contains a <form method="POST" action="/Users/ConfirmAndUpdateAction">. It will render hidden inputs for each text box or other form element in your previous POST form.
User clicks submit on the second form to confirm fields
The action method ConfirmAndUpdateAction on your UsersController accepts an HTTP POST with the same viewmodel object that your other POST action did. However instead of returning another view, this time it saves the data in your repository and redirects.

How to call a Controller from a PartialView in MVC3

I have a PartialView which I need to create a button on, and once a user clicks on this button, it must send a HTTPGET to a controller that receives the model. How do I call the HTTPGET action from the PartialView?
Any idea as to how to do this in MVC3?
may be this solution work :
<form method="get" action="controllerName" enctype="multipart/form-data">
#html.partial("viewName")
<input type="submit" value="Send" ... />
</form>
There are a few ways that you can achieve this. The easiest way is to use an ajax request to send the data back to the controller using jQuery (http://api.jquery.com/jQuery.get/). However I would not use a HTTP GET for this. Although not enforced it is best to stick to using the HTTP verbs in the way that they were intended ie GET is for receiving data, POST is for sending data to the server.
use this to create the form in your partial view,
#{using (Html.BeginForm("Create", "Person", FormMethod.Get, new {
enctype = "multipart/form-data",
id = "<id of the form>" }))
{
//body of your form
}
Here you can see that, type of the form method has been passed in to the Html.BeginForm method as "FormMethod.Get". If you want to sent the response to a Post method, uset "FormMethod.Post".

MVC: what code gets called when you click the "submit" button?

MVC newbie question; I'm learning by playing around rather than Reading The Manual... :)
I see when I create an "Edit" view that the auto-generated view includes a "submit" button:
<input type="submit" value="Save" />
But what code gets called behind the scenes to do this save? Specifically, the model underlying this view has its own fancy save logic in code that I would want to call. How do I get the view to invoke my code instead of whatever standard code is being called invisibly behind the scenes?
It's not the button that defines what happens, but the form itself. The button of type submit (one per form) just triggers the form submission, which is handled by the form itself.
A form has an action - e.g.:
<form name="input" action="users/save" method="post">
<!-- Form content goes here -->
<input type="submit" value="Submit" />
</form>
The action is an URL and what happens is that the browser collects the values of all the fields in the form (<input...>) and posts them to the specified url.
In ASP.NET MVC forms are usually defined using the Html helpers, so that building the URL for the form action is delegated to ASP.NET MVC. For the above for example:
<% using(Html.BeginForm("Save", "Users")) %>
<% { %>
<!-- Form content goes here -->
<input type="submit" value="Save" />
<% } %>
Which in this case will create a url /users/save and the form will post to that url. That in terms will trigger the ASP.NET routing which will handle the /users/save url and break it into chunks so that it knows that it has to invoke the "Save" action method on the "Users" controller class. It will then read all the incoming field name-value pairs and try to map them to the method parameter names if any.
It would call whatever public action method the form action is pointing to on your controller. You can then call save on the view model.
public virtual ActionResult Save(MyViewModel model) {
model.Save();
--- more code to do stuff here
}
Set your form action to MyController/Save
You can also use using (Html.BeginForm... in your code to point the form to a specific action method on a specific controller.
when you click submit button, request goes to the HTTp Module which directs it to corresponding controller action. when edit view is created from template the post address of the form is same as of the edit form i.e if you are visiting /home/edit you can see following html in form's opening tag
<form method="post" action="/home/edit">
you can have another action method that only accepts post requests like
[HttpPost]
public ActionResult Edit(int id, ViewModel model)
{
//put your logic here handling submitted values
}
HttpPost attribute tells that it will only handle post request as opposed to get requested used to render the form
it calls the Action method defined in the action part of the form element
eg:
<form action="/Account/LogOn" id="loginForm" method="post">
The LogOn action in the Account controller will be invoked in this form
The ViewPage has a BeginForm Method using (Html.BeginForm() at the top which would render the FormTag. This method has a overload which takes ActionName and controller Name. So you can specify the action in your controller which has to be called.

Categories