在异步站点中使用重力形式

Using gravity forms with an asynchronous site

我有一个使用 angular 处理 ajaxed 页面加载的 wordpress 网站。直接加载页面时,重力会按预期形成加载。如果您从非重力表单页面加载然后导航到带有表单的页面,您将一无所获。

这可能与表单下方嵌入的脚本 grav 表单有关。所以我想知道是否有办法在通过 ajax.

加载后初始化表单

我可以使用一些 html、jquery 魔法在页面加载后通过 ajax 获取表单 functions.php:

gravity_form_enqueue_scripts( $form_id, true );
echo gravity_form($form_id, false, false, false, null, true, 12, true);

当我将结果注入 DOM 时,我得到了这个控制台错误:

gformInitSpinner is not defined

即使我以新的 html 为目标并显示以 html 形式出现的表单,我也会得到一个无法正常工作的大量畸形表单。很明显,因为脚本没有得到评估,而且 js 错误无论如何都会阻止它。

所以有谁知道是否有办法让重力形式与异步站点一起工作?或者,如果您可以使用 ajax?

加载功能表单

我无法用 gravity_form_enqueue_scripts 填充入队系统,因为随时可能生成任意数量的表格。这不是一个实际的解决方案。

好吧,不感谢重力形式开发团队和整个互联网,我们为我们所有人提供了一个解决方案,我们的任务似乎是一个非常常用的插件的明显使用...

首先,设置您的 functions.php 文件,使其能够处理此问题:

// filter the Gravity Forms button type
add_filter( 'gform_submit_button', 'form_submit_button', 10, 2 );
function form_submit_button( $button, $form ) {
    return "<button class='btn btn-green' type='submit' id='gform_submit_button_{$form['id']}'>Submit</button>";
}

// Hook up the AJAX actions
add_action( 'wp_ajax_nopriv_gf_button_get_form', 'gform_ajax_get_form' );
add_action( 'wp_ajax_gf_button_get_form', 'gform_ajax_get_form' );

// Add the "button" action to the gravityforms shortcode
// e.g. [gravityforms action="button" id=1 text="button text"]
add_filter( 'gform_shortcode_form', 'gform_shortcode', 10, 3 );

function gform_shortcode( $shortcode_string, $attributes, $content )
{
    $a = shortcode_atts( array(
        'id' => 0,
        'text' => 'Show me the form!',
    ), $attributes );

    $form_id = absint( $a['id'] );

    if ( $form_id < 1 ) {
        return 'Missing the ID attribute.';
    }

    $ajax_url = admin_url( 'admin-ajax.php' );

    $html = sprintf('<div ng-controller="GavityFormController as garvityFormCtrl" ng-init="init(\'%s\', \'%s\')"><div class="gform_container" ng-include="form"></div></div>', $form_id, $ajax_url);

    return $html;
}

function gform_ajax_get_form(){
    $form_id = isset( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0;
    $form = gravity_form($form_id, false, false, false, false, true, 0, false);

    $form = str_replace('text/javascript', 'text/ng-javascript', $form);
    $form = str_replace('<script ', '<script lazy-js ', $form);

    echo $form;

    die();
}

add_filter("wp_footer", "init_gf_scripts");
function init_gf_scripts() {
    global $wpdb;

    //obviously change this if your prefix is different
    $sql = "SELECT `id` FROM `wp_rg_form` WHERE `is_active` = 1 AND `is_trash` = 0";
    $res = $wpdb->get_results($sql);
    foreach($res AS $r)
    {
        gravity_form_enqueue_scripts( $r->id, true );
    }
}

下一步可能会有所不同,具体取决于您设置主 js 文件的方式。必要的要点如下。通常还有很多,但希望您能理解。

(function(){
    require('./directives/forms/form');

    var util = require('./util');

    var app = angular.module('yourapp', [
        'yourapp-form',
    ])...

util.js ... 可能是一个普通文件。我不确定它是否真的与实际问题有任何关系,但它是表单组件所必需的,所以你去吧:

module.exports = (function() {
    var api = {
        isMobileOrSmaller: function () {
            return $(window).width() < 681
        },
        findByProp: function (data, value, prop) {
            prop = prop || 'id';
            return $.grep(data, function(e){ return e[prop] == value; });
        },
        getIndexOf: function (collection, value, prop) {
            prop = prop || 'id';
            return collection.map(function (e) { return e[prop] }).indexOf(value);
        },
        roundTo: function (value, to) {
            to = to || 10;
            return Math.floor(value/to) * to;
        },
        debounce: function(func, wait, immediate) {
            var timeout;
            return function() {
                var context = this, args = arguments;
                var later = function() {
                    timeout = null;
                    if (!immediate) func.apply(context, args);
                };
                var callNow = immediate && !timeout;
                clearTimeout(timeout);
                timeout = setTimeout(later, wait);
                if (callNow) func.apply(context, args);
            };
        },
        getScrollbarWidth: function () {
            return $(window).width();// - $('#siteBody > div').width();
        },
        getRandomInt: function (min, max) {
            return Math.floor(Math.random() * (max - min + 1)) + min;
        }
    };

    return api;
})();

以及表单指令...

/directives/forms/form.js

module.exports = (function() {
    var api = {};

    var form = angular.module('yourapp-form', [
    ]).directive('lazyJs', [function () {
        return {
            restricted: 'A',
            link: function (scope, element) {
                var code = element.text();
                var tmpFunc = new Function(code);

                scope.$on('GavityFormController::includeContentLoaded', function () {
                    tmpFunc();

                    if(window['gformInitDatepicker']) {
                        gformInitDatepicker();
                    }

                    if (window['gformInitPriceFields']) {
                        gformInitPriceFields();
                    }
                })
            }
        }
    }]).controller('GavityFormController', ['$scope', '$rootScope', '$element', '$http', function ($scope, $rootScope, $element, $http) {
        var panel = this,
            formId = 0; 

        $scope.form = '';
        $scope.init = function (id, url) {
            formId = id;
            $scope.form = url + '?action=gf_button_get_form&form_id=' + id
        }

        $scope.$on('$includeContentLoaded', function(e, src){
            if ($('#gform_wrapper_' + formId).length > 0) {
                $scope.$broadcast('GavityFormController::includeContentLoaded');
            }
        });
    }]);

    //registerring componenets
    var radio = require ('./radio');
    radio.register(form);

    var select = require ('./select');
    select.register(form);

    var text = require ('./text');
    text.register(form);

    var check = require ('./check');
    check.register(form);

    var textarea = require('./textarea');
    textarea.register(form);

    api.form = form;


    return api;
})();

这些都是必需的表单组件文件:

radio.js:

module.exports = (function() {
    var api = {};

    api.register = function (form) {
        form.directive('myappRadio', function(){
            return {
                restricted: 'E',
                transclude: true,
                replace: true,
                scope: {
                    model: '=model'
                },
                template: function ($element, $attrs) {
                    return '<div class="ipt ipt-radio"> \
                                <div  ng-transclude></div> \
                                <label for="' + $attrs.for + '">' + $attrs.label + '</label> \
                            </div>';

                }
            }
        });
    }


    return api;
})();

select.js:

var util = require('./../../util');

module.exports = (function() {
    var api = {};

    api.register = function (form) {
        form.directive('select', ['$timeout', function($timeout){
            return {
                restricted: 'E',
                link: function($scope, $element, $attrs) {
                    $timeout(function () {
                        Selectize.define('input_modify', function(options) {
                            var self = this;

                            this.setup = (function() {
                                var original = self.setup;
                                return function() {
                                    original.apply(this, arguments);

                                    this.$control.find('input').attr('id', '');
                                };
                            })();
                        });

                        $($element).selectize({
                            plugins: ['remove_button', 'input_modify']
                        });
                    }, 10);
                }
            }
        }])
    }


    return api;
})();

text.js

module.exports = (function() {
    var api = {};

    api.register = function (form) {

        form.directive('myapptext', function(){
            return {
                restricted: 'E',
                scope: {
                    model: '=model',
                    ngrequired: '='
                },
                link: function(scope, element, attrs, controllers) {
                    var panel = this;

                    scope.isActive = scope.model !== '';
                    scope.required = false;

                    if (attrs.required === "")
                        scope.required = true;

                    if (typeof scope.ngrequired !== "undefined")
                        scope.required = scope.ngrequired;

                    scope.onEnter = function () {
                        scope.isActive = true;
                    }

                    scope.onLeave = function () {
                        if (scope.model == '' || typeof scope.model == 'undefined'){
                            scope.isActive = false;
                        }
                    }

                    scope.$watch('ngrequired', function(value){
                        scope.required = scope.ngrequired;
                    });
                },
                template: function (element, attr) {
                    var id = attr.id || 'frm-' + attr.name,
                        type = attr.type || 'text';
                        value = attr.value || '';
                    return '<div class="ipt-text-wrappper" ng-class="{\'m-active\': isActive}"> \
                                <input ng-required="required" ng-focus="onEnter()" ng-blur="onLeave()" ng-model="model" id="' + id + '" type="' + type + '" name="' + attr.name + '" value="' + value + '" class="ipt ipt-text"> \
                                <label ng-click="onEnter()" for="' + id + '">' + attr.label + '</label> \
                            </div>';
                }
            }
        });
    }


    return api;
})();

check.js:

module.exports = (function() {
    var api = {};

    api.register = function (form) {
        form.directive('myappCheck', function(){
            return {
                restricted: 'E',
                transclude: true,
                replace: true,
                scope: {
                    model: '=model'
                },
                template: function ($element, $attrs) {
                    return '<div class="ipt ipt-radio"> \
                                <div  ng-transclude></div> \
                                <label for="' + $attrs.for + '">' + $attrs.label + '</label> \
                            </div>';

                }
            }
        });
    }


    return api;
})();

textarea.js:

module.exports = (function() {
    var api = {};

    api.register = function (form) {
        form.directive('myapptextarea', function(){
            return {
                restricted: 'E',
                scope: {
                    model: '=model',
                    ngrequired: '='
                },
                link: function(scope, element, attrs, controllers) {
                    var panel = this;

                    scope.isActive = scope.model !== '';
                    scope.required = false;

                    if (attrs.required === "")
                        scope.required = true;

                    if (typeof scope.ngrequired !== "undefined")
                        scope.required = scope.ngrequired;

                    scope.onEnter = function () {
                        scope.isActive = true;
                    }

                    scope.onLeave = function () {
                        if (scope.model == '' || typeof scope.model == 'undefined'){
                            scope.isActive = false;
                        }
                    }

                    scope.$watch('ngrequired', function(value){
                        scope.required = scope.ngrequired;
                    });
                },
                template: function (element, attr) {
                    var id = attr.id || 'frm-' + attr.name,
                        value = attr.value || '';
                    return '<div class="ipt-text-wrappper" ng-class="{\'m-active\': isActive}"> \
                                <textarea ng-required="required" ng-focus="onEnter()" ng-blur="onLeave()" ng-model="model" id="' + id + '" name="' + attr.name + '" class="ipt ipt-textarea">' + value + '</textarea> \
                                <label ng-click="onEnter()" for="' + id + '">' + attr.label + '</label> \
                            </div>';
                }
            }
        });
    }


    return api;
})();

就是这样。我个人通过调用 gravity_form 函数在 php 中调用它:

<?php echo gravity_form(1, false, false, false, '', true, 12); ?>

但我认为 WYSIWYG 中的基本嵌入式表格也可以使用。

这不是我自己写的,所以我不确定我是否可以回答问题,但如果你有问题,请随时提问