「Webサービスを(少しずつ)構築する」 第5回
ライブラリなしでネイティブ(ブラウザに標準で装備されている)関数だけでもAjaxは実現できるが、
コードが複雑になるのを避けるためにはライブラリの使用は有効。
Ajaxでは、クライアントからサーバへのHTTP通信が発生しても ページ遷移は起きない。
この章では、Ajaxに基づいて、 ページ遷移を行なわずに、 新規入力され受理されたデータを、 (画面上の)memo一覧の先頭に挿入表示させる (他の部分は変化しない)ことで、
ことが期待できる。
概要:
実体:
例えば以下のような2行からなるHTMLファイルを作成し、
<!doctype html>
<script src='http://code.jquery.com/jquery-latest.min.js'></script>
$
)を入力してみる(値としては同じものが表示されるだろう)。$
は、jQueryの別名として用意されている。
$
は特殊文字ではなく変数名を構成できる文字の1つ(英数字と同じ扱い)。主な文法要素:
$
関数:2つの用途を知っておこう。
jQueryオブジェクトの生成:
// 前述のHTMLファイルを開いてブラウザのコンソールで
// 以下の(各行の)式を試してみよう
$(document)
$(document.body)
// 或いは、このページを表示中にコンソールを開いて試してみる
$('h1')
$('h2')
$('p')
$('#section-1')
$('.language-javascript')
$('<p>aaa</p>')
ready の糖衣構文:
ページを読み込んでプログラムの動作が開始できる状態になった時に呼び出されるコードを書くための関数が、 DOMのdocument要素(に対応した jQueryオブジェクト)に用意された readyメソッド。これを書くための 簡易構文として以下の(後の方の)記法が好んで使われている。
$(document).ready(function(){
// 初期化のためのコード...
})
// これは以下のように書いてもいい
$(function(){
// 初期化のためのコード
})
// またはダブルアローを用いて
$(()=>{
// 初期化のためのコード
})
$
(または、この先いちいち書かないが jQuery
)に (現在のページに実在する)DOM要素、あるいはセレクタを表す文字列(CSSセレクタの文法に準拠)を渡すと、
jQueryオブジェクトが(上記の例のように)生成される。
jQueryオブジェクトは1つのDOM要素を含むこともあるし、複数のDOM要素を含むこともある(0個のこともある)が、
個数によらず、jQueryオブジェクトに対する処理の書き方は同じでいい
getElementById
と getElementsByClassName
が違う種類のデータを返し、その処理の書き方も違っていたことと対比させてみよう。$
関数に HTMLの記法で表現した要素(複合的なものも含めて)を文字列として渡すと、それに相当する要素が生成される
そのままではページに組み込まれないので、組み込むための処理は別途必要になる。以下の例では appendTo
を使っているがいくつかのメソッドが用意されている
(Qiitaの記事「JQueryの目的の場所に要素を追加
」などを参照)。
$('<p>afoajwefai</p>').
appendTo(document.body)
参考資料
使い方
script(src指定)タグや、link(rel=stylesheet)タグでの読み込みは、Same Origin などの制約を受けないので、
ライブラリのソースファイルの読込元は以下のどちらでも構わない。
開発元などからダウンロードして、自分の(今作っている)Webサーバの静的コンテンツ用フォルダ(public/js など)に置く。
このとき srcパラメータの値は、’./js/jquery-3.1.1-min.js’ のような相対パス指定になるだろう。
開発元やCDNに置かれたファイルをURLで指定する。
(以下の手順は、必ずしもこの通りの順序で実施しないといけない訳ではなく、 考え方の筋道として便宜上順序立てたもの。)
を決めておこう。
/memo/add
で、サーバ側プログラム
router.post('/add',(req,res)=>{
let date=new Date().toLocaleString(),
memo=req.body.memo
db.memo.create({date:date,memo:memo}).
then((created)=>{
res.json({date:date,memo:memo,id:created.dataValues.id})
})
})
routes/memo.js
の、router.post(‘/add’) に関するコードだけを示した。jQueryを組み込む 1:
(views/memo.pugの変更箇所)
このダイアログにあるテキストボックス(下図)にある HTML断片をそのままコピー(右側のボタンコピーできる)して pugファイルに貼り付ける。場所としては、先頭部(doctypeやmetaタグの後ろぐらい)が適切だろう。
pugのファイルとして扱いにくいと感じる人は(以下の例のように pugの文法に変換してもいい。
script(src="https://code.jquery.com/jquery-3.3.1.min.js",
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=",
crossorigin="anonymous")
或いは行頭に(空のタグの直後とみなしてもいい)ピリオド ‘.’ を置いてその1レベル下にHTMLを直に書いた場合は、 (ピリオド以下はpug的にはテキストコンテントと同等に 扱われpugが加工はしないため) HTMLが複数行(HTMLの文法に沿って)分かれても大丈夫。
.
<script src=
"https://code.jquery.com/jquery-3.3.1.min.js"
integrity=
"sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
このCDN推奨の読込み方(HTTPS経由、ファイルのハッシュ値の検査つき)でなく、単純なHTTPスキームでのアクセス(srcパラメータのみ)をしてもかまわない。
jQueryを組み込む2:
(views/memo.pugの変更箇所)
script.
$(()=>{
// この中は次項で
})
$(document).ready(function(){...})
の糖衣構文であるこのブレースの中に、
jQueryで設定しておきたい初期設定(のうち、このページのDOM要素に直接作用するもの)を書いておく(次項)。ページ遷移からAjax呼出への変更:
(views/memo.pugの変更箇所)
//- form(method='post', action='/memo/add')
textarea(name='memo',rows="4" cols="40") 思ったこと記憶すべきこと input(type="submit" value="送信")
代わりに関数 send(後で作る)を呼ぶようjQueryで(ready時に)設定させる。
$(()=>{
$('input').click(send)
})
代わりに、formタグを生かしておいて、action属性を以下のように書く方法もある(method属性は不要になる)。
//- PUG
form(action='javascript:send()')
データの送受信:
(views/memo.pugの変更箇所)
function send(){
let memo=$('textarea').val() // textarea jQueryオブジェクトの .text() だと
// 現在の値ではなく初期値が得られてしまうようだ
$.post('/memo/add',{memo:memo},recv)
// もちろん 変数に代入せず memo(<- : の右側のほう)
// の代わりに上のjQuery式をそのまま渡してもいい
}
$.get
, $.post
などの
呼出(引数の渡し方)は同じ形式で、
の順。
コールバック関数(Ajax呼出に成功して帰ってきた値を処理するための関数)は、 ここでは recv(受信時の関数にありがちな名前)にしてあるが、 もちろん send, recv ともに、プログラマが好きな名前をつけていい。
function recv(data,stat,jqXHRn){ //
$('tbody tr:first'). // 画面幅の都合で2行に分けて表示しているが勿論続けてもいい
after(`<tr><td>${data.id}</td><td>${data.date}</td><td>${data.memo}</td></tr>`)
}
表の左端に表示する通番(id)として、 これまで画面(上から順に)で生成していたが、 データベース内で自動生成される idフィールドを使っても構わない (新しい順に表示するならばその方が自然な流れになるだろう) ので、それに応じた変更をしておいた。
each item in list -- この結果として、
-- index は使わないので削除した
tr
td= item.id -- ここが変更箇所
td= item.date
td= item.memo