建立一個簡單的 AJAX 表單

SilverStripe 對使用 AJAX 請求提交表單資料有相當好的支援。下面是如何設定一個基本表單的示例程式碼,該表單接受 AJAX 和傳統預設瀏覽器行為提交的提交(這是一種很好的做法)。

將表單新增到我們的控制器

首先,我們需要定義我們的形式; 你的 Page_Controller 應該是這樣的:

class Page_Controller extends ContentController {

    /**
     * A list of "actions" (functions) that are allowed to be called from a URL
     *
     * @var array
     * @config
     */
    private static $allowed_actions = array(
        'Form',
        'complete',
    );

    /**
     * A method to return a Form object to display in a template and to accept form submissions
     *
     * @param $request SS_HTTPRequest
     * @return Form
     */
    public function Form($request) {
        // include our javascript in the page to enable our AJAX behaviour
        Requirements::javascript('framework/thirdparty/jquery/jquery.js');
        Requirements::javascript('mysite/javascript/ajaxforms.js');
        //create the fields we want
        $fields = FieldList::create(
            TextField::create('Name'),
            EmailField::create('Email'),
            TextareaField::create('Message')
        );
        //create the button(s) we want
        $buttons = FieldList::create(
            FormAction::create('doForm', 'Send')
        );
        //add a validator to make sure the fields are submitted with values
        $validator = RequiredFields::create(array(
            'Name',
            'Email',
            'Message',
        ));
        //construct the Form
        $form = Form::create(
            $this,
            __FUNCTION__,
            $fields,
            $buttons,
            $validator
        );

        return $form;
    }

    /**
     * The form handler, this runs after a form submission has been successfully validated
     *
     * @param $data array RAW form submission data - don't use
     * @param $form Form The form object, populated with data
     * @param $request SS_HTTPRequest The current request object
     */
    public function doForm($data, $form, $request) {
        // discard the default $data because it is raw submitted data
        $data = $form->getData();

        // Do something with the data (eg: email it, save it to the DB, etc

        // send the user back to the "complete" action
        return $this->redirect($this->Link('complete'));
    }

    /**
     * The "complete" action to send users to upon successful submission of the Form.
     *
     * @param $request SS_HTTPRequest The current request object
     * @return string The rendered response
     */
    public function complete($request) {
        //if the request is an ajax request, then only render the include
        if ($request->isAjax()) {
            return $this->renderWith('Form_complete');
        }
        //otherwise, render the full HTML response
        return $this->renderWith(array(
            'Page_complete',
            'Page',
        ));
    }

}

將這些函式新增到 Page_Controller 將使它們在所有頁面型別上可用 - 這可能是不可取的,你應該考慮是否更適合建立新的頁面型別(例如 ContactPage)以使此表單

在這裡,我們定義了以下方法:

  • 建立 Form
  • 表單處理程式(用於儲存或傳送提交的地方,這在 Form 成功驗證其資料後執行)
  • 一個 complete 動作,使用者將在成功完成表單提交後傳送給該動作。

自定義模板以便於更換內容

接下來我們需要設定模板 - 修改 Layout / Page.ss 檔案:

<% include SideBar %>
<div class="content-container unit size3of4 lastUnit">
    <article>
        <h1>$Title</h1>
        <div class="content">$Content</div>
    </article>
    <div class="form-holder">
        $Form
    </div>
        $CommentsForm
</div>

這是從預設的簡單主題中獲取的,稍加一點,表單現在包含在 <div class="form-holder"> 中,以便我們可以使用成功訊息輕鬆替換表單。

我們還需要建立一個 Layout/Page_complete.ss 模板 - 除了 form-holder div 之外,它將與上面相同:

<div class="form-holder">
    <% include Form_complete %>
</div>

接下來建立 Includes/Form_complete include - 使用 include 是很重要的,這樣我們就可以渲染頁面的這一部分來響應 AJAX 請求:

<h2>Thanks, we've received your form submission!</h2>
<p>We'll be in touch as soon as we can.</p>

建立 javascript 表單偵聽器

最後,我們需要編寫我們的 javascript 來通過 AJAX 傳送表單而不是預設的瀏覽器行為(將它放在 mysite / javascript / ajaxform.js 中):

(function($) {
    $(window).on('submit', '.js-ajax-form', function(e) {
        var $form = $(this);
        var formData = $form.serialize();
        var formAction = $form.prop('action');
        var formMethod = $form.prop('method');
        var encType = $form.prop('enctype');

        $.ajax({
            beforeSend: function(jqXHR,settings) {
                if ($form.prop('isSending')) {
                    return false;
                }
                $form.prop('isSending',true);
            },
            complete: function(jqXHR,textStatus) {
                $form.prop('isSending',false);
            },
            contentType: encType,
            data: formData,
            error: function(jqXHR, textStatus, errorThrown) {
                window.location = window.location;
            },
            success: function(data, textStatus, jqXHR) {
                var $holder = $form.parent();
                $holder.fadeOut('normal',function() {
                    $holder.html(data).fadeIn();
                });
            },
            type: formMethod,
            url: formAction
        });
        e.preventDefault();
    });
})(jQuery);

這個 javascript 將使用 AJAX 提交表單,並在完成後將淡出表單並將其替換為響應並將其淡入。

對於高階使用者:

在這個例子中,你網站上的所有表單都將被 ajaxified,這可能是可以接受的,但有時你需要對此進行一些控制(例如,搜尋表單不會像這樣工作)。相反,你可以稍微修改程式碼以僅查詢具有特定類的表單。

修改 Form 上的 Form 方法如下:

public function Form() {
    ...
    $form->addExtraClass('js-ajax-form');
    return $form;
}

像這樣修改 javascript:

$(window).on('submit', '.js-ajax-form', function(e) {
    ...
})(jQuery);

只有 js-ajax-form 類的表單才會以這種方式執行。