Support

Account

Home Forums General Issues Frontend form – post via ajax?

Solving

Frontend form – post via ajax?

  • I think I found a better way. So in 5.7.13 on line 13386 of /assets/js/acf-input.js there is some new logic that checks if the submit event has already bee prevented. This is why things stopped working. In the examples above we are setting preventDefault() for the submit event.

    Looking further in acf-input.js onSubmit we can see there are a few lines to run the form validation. That validation also eventually runs acf.doAction('submit', this.$el); when validation is successful.

    I could not find a way to get around the new logic in acf-input.js onSubmit so I still keep the preventDefault() on the submit event. But then run the validation method to submit the form. Something like this:

    
    $(document).on('submit', '.acf-form', function(e) {
        e.preventDefault();
    });
    
    $('.save').on('click', function(event) {
        if ($('.acf-form').length > 0) {
         	var valid = acf.validateForm({
    			form: $('.acf-form'),
    			event: acf.get('originalEvent')
    		});
        }
    });
    
  • In input.js the function acf.validateForm(args) is defined.
    This function can be used to trigger the validation of a frontend form.
    You can set args the following way:

    const args = {
    form: $form //required. The form you are submitting
    
    //the following default values ar set in validate:function(args) :
    
    // trigger event
    event: false,
    		
    // reset the form after submit
    reset: false,
    				
    // loading callback
    loading: function(){},
    				
    // complete callback
    complete: function(){},
    				
    // failure callback
    failure: function(){},
    				
    // success callback
    success: function( $form ){
       $form.submit();
       }
    }

    The default success callback starts submission when validation is is successful.
    You can replace this function by any other function.

    So you can block the validation and submission and call acf.validateForm:

    $('.cursus-info').on('click','.acf-button',function() {
    
    $('form#acf-form').on('submit',function(event){
    event.preventDefault();
    });
    
    args= {
    form: $form,
    reset: true
    success: function($form) {
    
    //Your ajax code or what ever you want to do
    
    }
    
    }
    
    acf.validateForm(args);
    	
    }

    In addition to submitting by ajax using acf.validateForm offers many other possibilities like validating without submisssion, do things when validation fails by defining the failure callback etc.

  • Hi Rob,

    Thank you so much for your response, are you please able to put it into a simple working example?

    perhaps just a single form field with a submit that reloads with ajax on the frontend?

  • Thanks everyone for posting their snippets, I thought I would share my compendium version of this just to bring it together as of Jan 2020 for other people looking to do something similar.

    I can’t dedicate a million hours to solving everyone’s issues in the future but hopefully this will be useful.

    My scenario was that I wanted to have a modal pop up on a button, load in an acf_form using a wordpress ajax request, and then submit it back via ajax before showing a success modal and letting the user return to the page.

    I have used jquery-modal for the modal library. Installed via npm install jquery-modal then enqueued the scripts/styles using normal wordpress features.

    I have used this tutorial for figuring out how to do ajax requests – https://benmarshall.me/wordpress-ajax-frontend-backend/

    The template that my WordPress ajax call returns is an acf_form() call:

    acf_form(array(
    	'post_id' => 'new_post',
    	'post_title' => true,
    	'new_post' => array(
    		'post_type' => 'yourposttypehere',
    		'post_status' => 'publish'
    	),
    	'form' => true,
    	'submit_value' => __("Add your post-type", 'textdomain'),
    ));
    

    I have a button to trigger it:

    
    	<a class="woocommerce-Button button js-addposttype-button" href="#">
    		<?php esc_html_e('Add post-type', 'textdomain'); ?>
    	</a>
    

    And this monster of JS:

    
        function setupAddPostTypeAJAX() {
            $('.js-addposttype-button').on('click', function (e) {
                e.preventDefault();
    
                this.blur(); // Manually remove focus from clicked link.
    
                var data = {
                    action: 'get_posttype_add_form',
                    security: myPostTypeAjax.security,
                };
    
                $.post(myPostTypeAjax.ajaxurl, data, function (response) {
                    // cant use jquery .wrap() here as it doesnt return the wrapped string
                    response = "<div class='modal'>" + response + "</div>";
                    var modalContent = $(response).appendTo('body');
                    acf.do_action('append', modalContent);
    
                    var $form = modalContent.find(".acf-form");
    
                    $form.on('submit', function (event) {
                        event.preventDefault();
                    });
    
                    modalContent.modal();
    
                    $form.find('.acf-form-submit .acf-button').on('click', function () {
                        args = {
                            form: $form,
                            reset: true,
                            success: function ($form) {
                                // Fix for Safari Webkit – empty file inputs kill the browser
                                // https://stackoverflow.com/a/49827426/586823
                                let $fileInputs = $('input[type="file"]:not([disabled])', $form)
                                $fileInputs.each(function (i, input) {
                                    if (input.files.length > 0) {
                                        return;
                                    }
                                    $(input).prop('disabled', true);
                                })
    
                                var formData = new FormData($form[0]);
    
                                // Re-enable empty file $fileInputs
                                $fileInputs.prop('disabled', false);
    
                                acf.lockForm($form);
    
                                $.ajax({
                                    url: window.location.href,
                                    method: 'post',
                                    data: formData,
                                    cache: false,
                                    processData: false,
                                    contentType: false
                                }).done(response => {
                                    acf.unlockForm($form);
                                    // show new modal saying posttype added
                                    var modalSuccessMessage = '<div class="modal">Your posttype has been added.</div>';
                                    $(modalSuccessMessage).appendTo('body').modal();
                                    
                                    // could also fire off a wordpress ajax here to update the underlying page data
                                    // if you are display a list of some kind of posttype and adding to it with this
                                });
                            }
                        }
    
                        acf.validateForm(args);
                    });
                });
            });
        }
    

    Its a combination of the various snippets that I’ve found throughout these forums so MASSIVE thanks to the people that have done the work on this before me. It would have been so many more hours of work without your helpful posts. I’m really grateful.

    As I understand it, this will support file uploads in your form of you have file fields. If you do then check the official acf_form page docs as there is an extra thing you will need to do for the wp uploader.

    Good luck everyone!

  • A follow up to this, that might help people out wanting to get the new post_id.

    It’s difficult to get the post_id back when you use an acf_form to make a new_post.

    In the end I solved it by hooking the acf_form_head in at the wp action hook.

    Then I handled the acf/submit_form and short circuited the reply with wp_send_json_success

    So I registered these hooks:

    
    public function plugin_init()
    {
        add_action('wp', array(&$this, 'acf_form_handler'));
        add_action('acf/submit_form', array(&$this, 'acf_checkout_prevent_pet_redirect'), 10, 2);
    
    }
    

    And used this:

    
            /**
             * Inject the ACF form handler on checkout pages
             */
            public function acf_form_handler()
            {
                if (is_checkout()) {
                    acf_form_head();
                }
            }
    

    For me, I needed them in the is_checkout() pages only. Tweak your code as required.

    The wp event is the first event that you can use conditionals, but its before any output so you can override the reply later on.

    The documentation is a bit misleading here as in one place it just says put acf_form_head() before the wp_head but somewhere else it does say before any html. Most of the time the first is fine but if you want to put your own json reply in its place then you need the wp hook.

    
            /**
             * Prevent redirect on AJAX pet create
             */
            public function acf_checkout_prevent_pet_redirect($form, $post_id)
            {
                if (is_checkout()) {
                    if ($form['post_id'] === "new_post") {
                        // fix "pet" post type creation
                        if ($form['new_post']['post_type'] == 'pet' && $form['new_post']['post_status'] == 'publish') {
                            // cannot alter $form['return'] object,
                            // so it's safe to just die here,
                            // to avoid the redirect issue
                            exit;
                        }
                        
                        // fix "prescription" post type creation
                        if ($form['new_post']['post_type'] == 'prescription' && $form['new_post']['post_status'] == 'publish') {
                            wp_send_json_success(array(
                                'post_id' => $post_id
                            ));
                            exit;
                        }
                    }
                }
            }
    

    (The redirect issue that I mention in the comments is probably something that you have come across – the response tries to redirect to (site)/admin-ajax.php?updated=true which gives a silent 400 error.)

    Then in my javascript, the response is now a javascript object. So merge this into the same part of the reply above:

    
                acf.lockForm($form);
    
                jQuery.ajax({
                  url: window.location.href,
                  method: 'post',
                  data: formData,
                  cache: false,
                  processData: false,
                  contentType: false,
                }).done(response => {
                  acf.unlockForm($form);
                  console.log(response);
                  if(response.success) {
                    console.log(response.data.post_id);
                  }
                  addFormSuccessCallback(response.data.post_id);
                });
    
Viewing 5 posts - 26 through 30 (of 30 total)

The topic ‘Frontend form – post via ajax?’ is closed to new replies.