しゃかまる

2014.12.25

JSでページ遷移しないフォームを作る(Advent Calendar 24日目(仮))

こんにちは、Advent Calendar 24日目(仮)を担当する村上です。
昨日の紹介と違う理由は推して知るべしです。

前回と前々回がゆるふわ記事だったのでマジメな記事です。
今回は素のJSでページ遷移しないフォームを作った話を書こうと思います。

目的

ページ遷移しないフォームを作ることが目標です。
フレームワークやAltJSは使わずに、素のJSを使います。

前提条件

以下の通りです。

  1. 編集, 確認, 完了ページで構成される
  2. 確認に遷移する前にvalidateを行う
  3. 確認ページ後にフォームデータの保存やメール送信を行う
  4. ページ遷移はしない
  5. ajax部分を1から実装するのはさすがにアレなのでjQueryにお任せ
  6. 細かいルーティングは行わない

validateや保存・メール送信処理はバックエンドで行っています。
バックエンドは実際にはPHPで実装したのですが、今回の記事とはずれる話題なので割愛します。
概要だけ書くと、JSからajaxでPOSTして、戻り値をjsonで受け取っています。
なお、セッション管理はPHP側でやっています。

実装

実際に行った実装についてまとめていきます。

方針

実装するフォームは、大きく分けるとを以下の5つに分けられます。

  • 編集画面を表示 (GET)
  • validateを行って結果によってエラーを表示/確認画面に遷移 (POST)
  • 確認画面を表示 (GET)
  • フォームの保存処理を行う (POST)
  • 完了ページを表示 (GET)

それぞれのフェーズで叩かれるHTTPのメソッドを()内に記載しています。
実際に画面に表示する内容は、編集, 確認, 完了の3ページです。
意味があるのか怪しい気もしますが、PRGに則っています。

描画されるページはそれぞれページ内でのイベントを持っていますが
独立しているべきなので、お互いに影響を与えないようにします。

コード

だいぶはしょっていますが、実際には以下のようになりました。

大体のoutlineはこのようになりました。
だいぶ省いたもののさすがに長いですね…

分類した機能ごとに、いわゆるclass的な作りにしています。

では細かく解説していきます。

大まかな作り

まず、全体で共通してprocessing変数を参照します。
GETやPOSTの処理が同時に走って処理が混在しないようにするためです。

GET処理はgetPage, POST処理はdoPostがそれぞれ担っています。
引数でコールバックを渡して、ajaxが正常終了したら任意の処理を実行できるようにしています。

GET
Edit, Confirmクラスには

  • getUrl (ページのURLを返す)
  • init (ページ描画後に行いたい初期処理)
  • pageEvent (ページのイベントハンドラ定義)

というメソッドを定義しています。

pageEventはjQueryを使うために用意したメソッドです。
イベントハンドラをjQueryに任せているので、ページごとのイベントの定義を行う場合は
このメソッドを使用します。(onとかちゃんと使えば無くせるんですが)
初期処理としてinitで行うべきなのですが、initをjQueryと切り離したかったため
pageEventメソッドを用意してinitから呼んでいます。

getEditPage, getConfirmPageはそれぞれeditページ、confirmページのHTMLを取得します。
getPageのdataTypeがhtmlであるように、それぞれhtmlをレンダリングするHTMLを取得して描画しています。
それぞれ、コールバックでinitメソッドをコールするようになっているので、レンダリング後に初期処理が走ります。

POST
Validate, Submitクラスは

  • getUrl
  • init

を持っています。処理内容は上記のものと同じです。

本来はベースとなるクラスを定義して、Object.Createしてやるべきですね。
runのようなメソッドを作って子供のclassで流れを意識しなくていいようにしたいところです。
あ、今さらですがES5向けで考えてます。ES6ならおとなしくclassを使います。

このように、各フェーズでget|postしたら、そのクラスのinit処理を呼ぶようにしています。
これでフェーズごとの処理をそれぞれのクラスに委譲できるので、ごちゃごちゃせずに記述が混在せずスッキリしました。

なお、完了ページは別で用意していたので、 location.href で飛ばしています。

まとめ

できるだけ綺麗にページ遷移しないフォームを書こうと思って始めたものですが
それなりにまとまったかと思います。
JSは好き勝手に書けるせいで訳の分からない記述になってしまいがちですが、ある程度は綺麗に
メンテしやすい形に出来たんじゃないかと思います(主観ですがw)
何かのご参考になれば幸いです。

AdventCalendar最終日は t_ishida 先生です。