Action executes twice on submit - asp.net-mvc-3

My controller action is being executed twice. Fiddler shows two requests and responses, and for the first one has an icon that indicates "Session was aborted by the client, Fiddler, or the Server."
But I can't figure out where this is happening, or why.
Here are the specifics:
I have a section of a view (ThingFinancials) that looks like this:
#{ using (Html.BeginForm("ConfirmThing", "Thing", null, FormMethod.Get, new { id = "frmGo" }))
{
#Html.HiddenFor(model => model.ThingID)
<button id="btnGo">
Thing is a Go - Notify People</button>
}
}
The javascript for btnGo looks like this:
$("#btnGo").click(function () {
var form = $("#frmGo");
form.submit();
});
The action (stripped down) looks like this:
public ActionResult ConfirmThing(int thingID)
{
[do some database stuff]
[send some emails]
var financials = GetFinancials(thingID);
return View("ThingFinancials", financials);
}
The only thing that looks unusual to me is that the URL you'd see would start out as [Website]/Thing/ThingFinancials/47, and after submission the URL would be [Website]/Thing/ConfirmThing?ThingID=47.
(If you're wondering why the Action name doesn't match the View name, it's because there are multiple form tags on ThingFinancials, and they can't all have the same action name.)
Is there a Server.Transfer happening behind the scenes, or something like that?

If you are using a submit button then you need to cancel the default behaviour when submitting with javascript, otherwise you will submit it twice. Try this:
$("#btnGo").click(function () {
var form = $("#frmGo");
// event.preventDefault(); doesn't work in IE8 so do the following instead
(event.preventDefault) ? event.preventDefault() : event.returnValue = false;
form.submit();
});

Your int thingID is a query string parameter that stays with the request. At the end of ActionResult ConfirmThing(int thingID), all you're doing is returning a view. If you'd rather see the clean URL ([Website]/Thing/ThingFinancials/47) you can make the following changes.
public ActionResult ConfirmThing(int thingID)
{
[do some database stuff]
[send some emails]
// This logic is probably in the 'ThingFinancials' action
// var financials = GetFinancials(thingID);
// I'll assume we're in the same controller here
return RedirectToAction("ThingFinancials", new { thingID });
}

This is because of your jquery event just add stopImmediatePropagation() to your jquery event.
$("#btnGo").click(function (event){
event.stopImmediatePropagation();
});

Related

Return a warning (not an error) via Ajax remote validation

I have an MVC Ajax callback that checks to see if a user input is valid. This callback is invoked via the [Remote] attribute on the associated model property.
I've changed my design, and I've decided that I would really like to warn the user if the value is incorrect, but I don't want the incorrect value to prevent model validation.
A quick search turns up several threads describing very involved solutions to the general problem of wiring up "unobtrusive warnings" similar to the "unobtrusive validation" magic baked into MVC (for example this SO post). I'm not looking for a general solution, and I don't want to spend a lot of time and energy on this, but I'm wondering if some Ajax guru knows of something I can return from the Ajax server routine that would have the effect of causing the unobtrusive validation client-side code to put up the message without triggering the validation error.
FYI, my existing server-side code looks like this:
public async Task<ActionResult> CouponCodeExists(string couponCode, int? planId)
{
if (some_logic) {
return Json("Coupon code is already taken", JsonRequestBehavior.AllowGet);
} else {
return Json(true, JsonRequestBehavior.AllowGet);
}
}
A RemoteAttribute is a validation attribute and triggering it will add a validation error to jQuery.validate.js and prevent the form from submitting. If you just want a warning message, and still allow the form to submit, you can just make your own ajax call in the inputs .change() event.
Assuming you have #Html.TextBoxFor(m => m.couponCode) in the view, add a placeholder for the message - say <div id="couponwarning">Coupon code is already taken</div> and style in as display: none;. Then add the following scripts
var url = '#Url.Action("CouponCodeExists")';
var warning = $('#couponwarning');
$('#couponCode').change(function() {
var code = $(this).val();
var id = .... // the value of your planId input?
$.get(url, { couponCode: code, planId: id }, function(response) {
if (response) {
warning.show();
}
});
});
$('#couponCode').keyup(function() {
warning.hide();
});
and the method can just return true to display the message, or null
if (some_logic) {
return Json(true, JsonRequestBehavior.AllowGet);
} else {
return Json(null, JsonRequestBehavior.AllowGet);
}

Ajax post in mvc returns no success

I have written an Ajax POST to submit a form, but it fails to succeed.
The Ajax POST comes through to the action in the controller which in turn will return a PartialView, which is also made correctly as I can debug this.
The goal is to let the user add a new log, whatever the outcome (failed captcha, failed validation) a Partialview will be returned with the right ViewBag errors messages. Razor takes care of the rest. This way the user will not be redirected to other pages.
When the Ajax succeeds it should put the data in the right <div>. The code is a copy of a working Ajax GET only changing it into a POST and providing the formdate serialized.
tldr; Ajax POST to Action in controller works, the partialview is rendered and returned yet the Ajax failes to succeed making it unable to update the designated <div>
Ajax call:
<script>
$('#add-log').click(function (event) {
event.preventDefault();
$.ajax({
url: $('#add-log').attr('data-url'),
type: 'post',
data: $("#log-form").serialize(),
succes: function (data) {
$('#add-log').attr('data-target').html(data);
console.log("Succes");
}
});
}
</script>
Controller:
[HttpPost, ValidateInput(false)]
[Authorize(Roles = "Student")]
public ActionResult Add(object sender, Log log, string returnURL, bool SendEmail)
{
ViewBag.Vulns = TempData["Vulns"];
//region Captcha: Here we have our Captcha settings
var response = Request["g-recaptcha-response"];
//secret that was generated in key value pair
const string secret = "Just a secret for our captcha, move along";
var client = new WebClient();
var reply = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}", secret, response));
var captchaResponse = JsonConvert.DeserializeObject<CaptchaResponse>(reply);
if (ModelState.IsValid && captchaResponse.Success)
{
db.Log.Add(log);
db.SaveChanges();
if (SendEmail)
{
//Emails are sent from here on out, but that's out of the scope
}
}
else
{
if (!captchaResponse.Success)
{
ViewBag.fillcaptcha = "Please fill in the captcha";
}
else
{
ViewBag.Wrong = "Something went wrong please try again";
}
ViewBag.returnUrl = returnURL;
ViewBag.domain = log.DomainId;
return PartialView(log);
}
}
There's more code but I left that out. Most important thing in the controller is just the last IF. I test the ajax by posting an empty log with no captcha resulting in a partialview with the same log and the viewbag.captcha error. This partialview is rendered but somehow ajax doesn't succeed.

Redirect after AJAX form submission

Using MVC 4, I have a partial view form which contains an #Ajax.BeginForm.
The form submits as expected, and the result is displayed asynchronously in my main view.
I want a condition on my controller that if a certain parameter is true on my form, then it redirects to a whole new page (instead of displaying the result in my main view).
When I tried return RedirectToAction, the whole view displays in the div that the form normally displays in, as opposed to ignoring the AJAX and redirecting to a completely new page.
Does anyone know how I can acheive this?
You can use return JavaScript to achieve it.
public ActionResult MyAction()
{
if (parameter)
{
return JavaScript("window.location = '" + Url.Action("Action", "Controller") + "'");
}
//Do something here
return PartialView("ParitalView", Model);
}
You could not perform RedirectToAction in a ajax call.
Just return a HttpStatusCodeResult and based on it perform redirect in Javascript
public ActionResult Save()
{
return new HttpStatusCodeResult(302,
"/Users/Details");
}
In Ajax Error function, set in AjaxOptions { OnFailure = "Error" }
function Error(response, status, error) {
window.location.href= response.statusText;
}

MVC3 call controller function on dropdown select

I have the following code in a partial view
Country Selector</label>
#Html.DropDownListFor(model => model.CountryGroup, Model.CountryCodes, new { id = "CountryGroup", name = "country-codes" })
#Html.ValidationMessageFor(model => model.CountryGroup, "*")
In the controller I have
public ActionResult ProcessRemoteOrder()
{
var a = 1;
return null;
}
I am assuming that when the code runs a break point on var a will be hit. it is not.
Can someone tell me where I can findout what how to get the function in the controller is run?
thnx
If you want to call the controller action when you select an item from the dropdown, you need to listen to the change event of the drop down and use jQuery ajax to make a call to the action method
$(function(){
$("#CountryGroup").change(function(){
$.get("#Url.Action("ProcessRemoteOrder","YourControllerName")",
function(data){
//do some thing with the response, in data variable.
});
});
});
To check whether it is running. Set a breakpoint in your code on the line you want to debug and when the code execute that line the breakpoint will be highlighted with yellow color.

MVC3 & Razor: How to structure forms & actions to allow for postback-like functionality?

I have a view with a drop down list. The default value for this is stored in a session variable. However, the user change change this, in which case new data is entered.
I have a change handler on the drop down:
#using (Html.BeginForm())
{
#Html.DropDownListFor(model => model.SelectedID,
new SelectList(Model.SelectValues, "Key", "Value",
Model.SelectedID), "", new { onchange = "this.form.submit()" });
... more fields ...
<input type="submit" name="Save" />
}
[HttpPost]
public ActionResult Index(ViewModel vm)
{
... decide if I update my data or save the changes ...
}
I tried wrapping the select in a separate form tag, but then the value of my SelectedID not updated in my view model.
How can I determine when the form is posted from a drop down change, and when it is posted from a button click?
If you don't want to reload the entire page when the user changes the selection of the dropdown you could use AJAX to silently trigger a request to a different controller action that will do the necessary updates. For example:
#Html.DropDownListFor(
model => model.SelectedID,
new SelectList(Model.SelectValues, "Key", "Value"),
"",
new {
id = "myddl",
data_url = Url.Action("update")
}
)
and then in a separate javascript file:
$(function() {
$('#myddl').change(function() {
var form = $(this).closest('form');
$.ajax({
url: $(this).data('url'),
type: 'POST',
data: form.serialize(),
success: function() {
alert('update success');
}
});
});
});
and finally you could have a controller action responsible for the update:
[HttpPost]
public ActionResult Update(ViewModel vm)
{
... this will be triggered everytime the user changes some value in the
droipdown list
}
The simplest way would be to simply attach some behavior to those element's events and set a hidden field with the event target (which by now, should sound very familiar to __EVENTTARGET).
Like so:
$('#someButton').click(function()
{
$('#someHiddenField').val('someButton');
});
$('#someDropDown').change(function()
{
$('#someHiddenField').val('someDropDown');
});
And then your action method could inspect this value and act appropriately.
HOWEVER
It sounds like you're thinking in an outmoded concept for MVC. If you really needed some new information, you should consider using some Ajax and then having one of your action methods return a partial view if you want to update part of the page.

Resources