简体   繁体   中英

Enable button that was disabled by javascript

I am disabling a button on first click to prevent a transaction from being submitted multiple times. If there is an error on screen, and I send them back to the form, the button is still disabled so they cannot resubmit the form.

This is my form with my javascript:

@using SuburbanCustPortal.sessions
@model SuburbanCustPortal.Models.PaymentModel.WebPayment


@{
  ViewBag.Title = "Make a payment!";
}

@if (CurrentCustomerSession.Current.TokenShowHideSettings.ShowPaymentScreenMessage)
{
  <div class="CompanyMessage">
    @Html.Raw(@CurrentCustomerSession.Current.TokenSettings.PaymentScreenMessage)
  </div>
}

@using (Html.BeginForm("WebPaymentSubmit", "Payment", FormMethod.Post))
{
    <div>
    <fieldset>
      <legend>Please enter the amount of the payment below.</legend>

      <div class="paymentPageMargin">

        <div class="paymentBlock">

          <div class="block_container">
            <div class="serviceBox1 paymentBlockTextLeft payment-label-nomargin">
              Account Number:
            </div>
            <div class="serviceBox2 paymentBlockText payment-label-nomargin">
              @CurrentCustomerSession.Current.Branch-@CurrentCustomerSession.Current.AccountNumber
            </div>
          </div>

          @if (CurrentCustomerSession.Current.CurrentCustomer.BudgetRate > 0)
          {
            <div class="block_container">
              <div class="serviceBox1 paymentBlockTextLeft payment-label-nomargin">
                Budget Rate:
              </div>
              <div class="serviceBox2 paymentBlockText payment-label-nomargin">
                $@string.Format("{0:F2}", CurrentCustomerSession.Current.CurrentCustomer.BudgetRate)
              </div>
            </div>

            <div class="block_container">
              <div class="serviceBox1 paymentBlockTextLeft payment-label-nomargin">
                Budget Balance:
              </div>
              <div class="serviceBox2 paymentBlockText payment-label-nomargin">
                $@string.Format("{0:F2}", CurrentCustomerSession.Current.CurrentCustomer.BudgetBalance)
              </div>
            </div>

          }
          else
          {

            <div class="block_container">
              <div class="serviceBox1 paymentBlockTextLeft payment-label-nomargin">
                Account Balance:
              </div>
              <div class="serviceBox2 paymentBlockText payment-label-nomargin">
                @string.Format("{0:F2}", CurrentCustomerSession.Current.CurrentCustomer.TotalBalance)
              </div>
            </div>
          }

        </div>

        @Html.ValidationSummary(true, "Submit was unsuccessful. Please correct the following errors.")

        <div class="paymentCardTypesMargin">

          @if ((bool)CurrentCustomerSession.Current.TokenSettings.CreditCardAcceptsVisa)
          {
            <img src="../Content/images/visa.jpg" alt="Visa Card" height="27" width="42" />
          }

          @if ((bool)CurrentCustomerSession.Current.TokenSettings.CreditCardAcceptsAmex)
          {
            <img src="../Content/images/amex.png" alt="Mastercard" height="27" width="42" />
          }

          @if ((bool)CurrentCustomerSession.Current.TokenSettings.CreditCardAcceptsMasterCard)
          {
            <img src="../Content/images/mastercard.jpg" alt="Mastercard" height="27" width="42" />
          }

          @if ((bool)CurrentCustomerSession.Current.TokenSettings.CreditCardAcceptsDiscover)
          {
            <img src="../Content/images/discover.gif" alt="Mastercard" height="27" width="42" />
          }

        </div>

          <div class="payment-label width300">
          Card Holder's Name
        </div>

        <div class="editor-field width200">
          @Html.TextBoxFor(m => m.NameOnCard, new { @class = "makePaymentTextLeft width200" })          
        </div>

        <div class="block_container">
          <div class="payment-label-nomargin serviceBox1 width205">
            <p>Billing Street Address</p>
          </div>
          <div class="payment-label-nomargin serviceBox2 width75">
            <p>Billing Zip Code</p>
          </div>
        </div>


        <div class="block_container">

          <div class="serviceBox1 width200">
            @Html.TextBoxFor(m => m.StreetAddress, new { @class = "makePaymentTextLeft width200" })            
          </div>


          <div class="serviceBox2">
            @Html.TextBoxFor(m => m.Zip, new { @class = "makePaymentTextLeft width75" })            
          </div>

        </div>

        <div class="payment-label">
          Credit Card Number
        </div>
        <div class="editor-field">
          @Html.TextBoxFor(m => m.CreditCardNumber, new { @class = "makePaymentTextLeft width200", autocomplete = "off" })
        </div>



        <div class="block_container">
          <div class="serviceBox1 width120">
            <p>Expiration Date</p>
          </div>
          <div class="serviceBox2 width150">
            <p>Security Code</p>
          </div>
        </div>

        <div class="block_container">

          <div class="serviceBox1 width30">
            @Html.TextBoxFor(m => m.CreditCardExpMonth, new { @class = "makePaymentTextLeft width30", @placeholder = "MM", autocomplete = "off" })
          </div>

          <div class="serviceBox3 width30">
            @Html.TextBoxFor(m => m.CreditCardExpYear, new { @class = "makePaymentTextLeft width30", @placeholder = "YY", autocomplete = "off" })
          </div>

          <div class="serviceBox4 padLeftCvv">
            @Html.TextBoxFor(m => m.CreditCardCcv, new { @class = "makePaymentTextLeft width40", autocomplete = "off" })
          </div>

        </div>

        <div class="payment-label">
          Payment Amount
        </div>
        <div class="payment-label-nomargin focus">
          @Html.TextBoxFor(m => m.Amount, "{0:F2}", new {@class = "makePaymentTextRight width90", autocomplete = "off"})
        </div>

        <div class="paymentButton">
          <p>
            <input id="saveButton" class="typicalbutton" type="submit" value="Pay Now" />
          </p>

          <script>
            // Find ALL <form> tags on your page
            $('form').submit(function () {
              // On submit disable its submit button
              $('input[type=submit]', this).attr('disabled', 'disabled');
            });
          </script>

        </div>

      </div>

    </fieldset>
  </div>
}

How do I reenable the button when the form fails to submit due to errors on the form?

EDIT1

This is my method in my controller that is being called on submit:

[Authorize]
[SessionExpireFilter]
public ActionResult WebPaymentSubmit(PaymentModel.WebPayment model)
{
  Console.WriteLine("WebPaymentSubmit Clicked!!");

  var control = Logging.StartLog();
  control.ClassName = System.Reflection.MethodBase.GetCurrentMethod().Name;

  try
  {
    Logging.WriteLog(control, "Start WebPaymentSubmit");

    var hasErrors = false;
    if( model.Amount <= 0)
    {
      hasErrors = true;
      ModelState.AddModelError("Amount", "Invalid amount.");          
    }

    if (string.IsNullOrEmpty(model.CreditCardNumber) || LuhnsTest.IsValidCreditCardNumber(model.CreditCardNumber))
    {
      hasErrors = true;
      ModelState.AddModelError("CreditCardNumber", "Invalid credit card number.");                    
    }

    if (hasErrors)
    {
      return View("WebPayment");
    }

The return View("WebPayment"); is how it is being sent back after the value checks.

EDIT2

Okay, I figured out why it is not posting. The PaymentModel [Required] is stopping the form from continuing which is why the form is not being reloaded.

If this is the case, how do enable the button if the required failed on my PaymentModel?

public class WebPayment
{
  [Required]
  [DataType(DataType.Text)]
  public string StreetAddress { get; set; }

  [Required]
  [DataType(DataType.Text)]
  public string Zip { get; set; }

  [Required]
  [DataType(DataType.Text)]
  public string NameOnCard { get; set; }

  [Required]
  [DataType(DataType.Text)]
  public string CreditCardNumber { get; set; }

  [Required]
  [DataType(DataType.Text)]
  public string CreditCardExpMonth { get; set; }

  [Required]
  [DataType(DataType.Text)]
  public string CreditCardExpYear { get; set; }

  [Required]
  [DataType(DataType.Text)]
  public string CreditCardCcv { get; set; }

  [Required]
  [DataType(DataType.Currency)]
  [DisplayFormat(DataFormatString = "{0:F2}", ApplyFormatInEditMode = true)]
  public decimal Amount { get; set; }
}

You would need to handle the response in the JavaScript using an Ajax call if you didn't want to page to refresh.

http://jsbin.com/caguzejopu/1/edit?html,js,console,output

That means updating your controller to return a response if the use makes a bad request

return new HttpStatusCodeResult(HttpStatusCode.BadRequest, "Payment declinded");

This might not be the best way, but couldn't you just set the button to enabled on page load? On the initial load, it wouldn't matter, but every load after that, it would be reset to enabled. That way every time you load the page it is explicitly enabled and then you can manipulate it however you like from there. Though this would only work if the page is reloaded after the form fails to submit.

If you are using postbacks than this code reenables button on every reload:

    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(FormCollection collection)
    {
        return View();
    }

If you are posting with some sort of javascript you will have to reenable within error handler.

The second thing I've notices is that you use jQuery in inline block of code. You have to be sure that the library is already loaded there. The workaround might be to put that code into the scripts section and render it after jQuery loading.

You could enable the buttons in the 'done' and 'fail' functions of an ajax call.

$('form').submit(function (e) {
    e.preventDefault(); // Prevent default submit action

    $('input[type=submit]', this).prop('disabled', true);

    // If you're using client side validation as well
    if ($(this).valid() === false) {
        $('input[type=submit]', this).prop('disabled', false);
        return;
    }

    // Submit manually with Ajax
    $.ajax({
        url: $('form').attr("action"),
        type: $('form').attr("method"),
        data: $('form').serialize(),
    }).done(function (data) {
        // If returning partial view
        //$("#your-form-container").html(data);

        // Else returning whole view
        $(document.body).html(data); // Haven't tested

        // I don't think you need this since the form is refreshed anyway
        $('input[type=submit]', this).prop('disabled', false);
    }).fail(function() {
        $('input[type=submit]', this).prop('disabled', false);
    });
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM