SQLForm.factory Pre-Submit Processing Using JavaScript

147 views
Skip to first unread message

Eliot Simcoe

unread,
Apr 25, 2016, 8:50:53 AM4/25/16
to web2py-users
I have a component that has a payment form that uses the Authorize.net gateway. I want to be able to display a bootstrap modal dialog with payment confirmation information before the form is actually submitted, but after the user clicks the submit button.

single_payment_form = SQLFORM.factory(
   
Field('tenant_name',    'string',        label="Tenant Name",    length=255),
   
Field('payment_amount', 'decimal(10,2)', label="Payment Amount", requires=IS_DECIMAL_IN_RANGE(0, None, "Enter a positive dollar amount"), widget=CurrencyWidget.With_Symbol('$')),
   
Field('payment_method', 'string',        label="Payment Method", requires=IS_IN_SET(payment_methods, zero='Please add a Payment Method to make payments' if not payment_methods else None), length=20),
    table_name
= "single_payment_form",
    _onsubmit
="return confirm_payment();",
    submit_button
= "Continue")

# process the single payment form
if single_payment_form.process(keepvalues=False).accepted:
       
...

I tried to set my onsubmit form attribute to a javascript function that will display the modal dialog, and cancel the form submission by returning false. When the user clicks the Edit Payment button on the modal dialog, the form should be re-enabled, but not submitted. Also it should not be reloaded. When the user clicks the submit payment button the form should be submitted normally and reloaded:

<div class="modal fade" id="payment-confirmation-dialog" tabindex="-1" role="dialog" aria-labelledby="payment-confirmation-dialog">
 
<div class="modal-dialog modal-lg" role="document">
   
<div class="modal-content">
     
<div class="modal-header">
       
<h4 class="modal-title">Payment Confirmation</h4>
     
</div>
     
<div class="modal-body" id="payment-confirmation-body">
     
<h2>confirmation stuff</h2>
     
</div>
     
<div class="modal-footer">
         
<a class="pull-left btn btn-default" type="button" href="javascript: edit_payment();">Edit Payment</a>
         
<a class="pull-right btn btn-primary" type="button" href="javascript: submit_payment();">Submit Payment</a>
     
</div>
   
</div>
 
</div>
</div>

<script type="text/javascript">
function confirm_payment() {
    $
('#payment-confirmation-dialog').modal({
        show
: true,
        backdrop
: 'static',
        keyboard
: false
   
});
   
   
return false;
}

function edit_payment() {
   
var $form = $('#single_payment_form_component form');
   
    $
('#payment-confirmation-dialog').modal('hide');
   
    $
.web2py.enableFormElements($form);
}

function submit_payment() {
   
var $form = $('#single_payment_form_component form');
   
    $
('#payment-confirmation-dialog').modal('hide');
    $form
.submit(function () { return true; });
    $form
.submit();
}
</script>

For some reason, my component is always submitted and reloaded... Always... even if I set the form's _onsubmit="return false;"

How can I stop the component from submitting and reloading when the submit button is pressed?

Thanks,
Eliot

Eliot Simcoe

unread,
Apr 26, 2016, 12:51:56 PM4/26/16
to web2py-users
In case anyone else ever has this problem, I will post my own solution. Web2Py traps all form submissions in web2py.js. To override this behaviour we need to add the "no_trap" class to the form declaration:

single_payment_form = SQLFORM.factory(
   
Field('tenant_name',    'string',        label="Tenant Name",    length=255),
   
Field('payment_amount', 'decimal(10,2)', label="Payment Amount", requires=IS_DECIMAL_IN_RANGE(0, None, "Enter a positive dollar amount"), widget=CurrencyWidget.With_Symbol('$')),
   
Field('payment_method', 'string',        label="Payment Method", requires=IS_IN_SET(payment_methods, zero='Please add a Payment Method to make payments' if not payment_methods else None), length=20),
    table_name
= "single_payment_form",

    _class
="no_trap",
    submit_button
= "Continue")

Then we need to reimplement that behaviour with a flag to indicate whether or not the confirmation has already happened. I used an already_confirmed data attribute on the form.


<script type="text/javascript">
function single_payment_form_trap() {
   
var $component = $('#single_payment_form_component');

   
var $form = $('#single_payment_form_component form');

   
var action = $component.attr('data-w2p_remote');
   
var target = 'single_payment_form_component';
   
    $form
.attr('data-w2p_target', target);
    $form
.attr('data-already_confirmed', 'false');
   
   
var url = $form.attr('action');
   
if ((url === '') || (url === '#') || $.web2py.isUndefined(url)) {
       
/* form has no action. Use component url. */
        url
= action;
   
}
   
    $form
.submit(function (e) {
       
var already_confirmed = $form.attr('data-already_confirmed');
       
       
if( already_confirmed == 'false' ) {
            $
.web2py.disableElement($form.find($.web2py.formInputClickSelector));
            $
.web2py.hide_flash();

           
            $
('#payment-confirmation-dialog').modal({
                show
: true,
                backdrop
: 'static',
                keyboard
: false
           
});

       
} else {
            $
.web2py.ajax_page('post', url, $form.serialize(), target, $form);
       
}
        e
.preventDefault();
   
});
   
    $form
.on('click', $.web2py.formInputClickSelector, function (e) {
        e
.preventDefault();
       
var input_name = $(this).attr('name');
       
if (!$.web2py.isUndefined(input_name)) {
            $
('<input type="hidden" />').attr('name', input_name)
           
.attr('value', $(this).val()).appendTo($form);
       
}
        $form
.trigger('submit');
   
});
};
single_payment_form_trap
();


function edit_payment() {
   
var $form = $('#single_payment_form_component form');
   
    $
('#payment-confirmation-dialog').modal('hide');
   
    $
.web2py.enableFormElements($form);
}

function submit_payment() {
   
var $form = $('#single_payment_form_component form');
   
    $
('#payment-confirmation-dialog').modal('hide');

    $form
.attr('data-already_confirmed', 'true');
    $form
.submit();
}
</script>

In the single_payment_form_trap function we shown the payment confirmation modal if the already_confirmed data attribute is false - otherwise we submit the form normally - this is taken almost directly from web2py.js.

I wouldn't call this a graceful solution - but it will work until an update to web2py brakes this assumed component submission algorithm.

I hope that someone finds this useful or at least aids in someone's understanding of exactly what happens in Web2Py when you click Submit in a form that has been loaded in a component.

Thanks,
Eliot
Reply all
Reply to author
Forward
0 new messages