新規会員登録機能というテイで、メールアドレス重複チェックをページ遷移無しで行うようにします。
このご時世なのでこんな機能は不要かと思われますが、勉強のためですので大目に見てください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.red {
color: #ff0000;
}
</style>
<script src="main.js"></script>
</head>
<body>
<form name="formbbs" id="formbbs">
なまえ<input type="text" name="your_name"><br>
メールアドレス<input type="email" name="email" id="email"><br>
<input type="submit" id="submit" value="送信">
</form>
</body>
</html>
'use strict';
document.addEventListener('DOMContentLoaded', main);
function main() {
const email = document.getElementById('email');
email.addEventListener('keyup', () => {
let val = email.value;
console.log(val);
if(val.match(/^[A-Za-z0-9]+[\w-]+@[\w\.-]+\.\w{2,}$/)) {
const url = 'db.php';
const post_options = {
method: 'post',
body: JSON.stringify({
"email": val,
}),
};
fetch(url, post_options)
.then( response => {
if(response.ok) {
return response.json();
}
throw new Error('エラーです。');
}).then( json => {
console.log(json);
if(json.errorFlg) {
const newP = document.createElement('span');
newP.id = 'warning';
newP.classList.add('red');
newP.textContent = json.msg;
const formbbs = document.getElementById('formbbs');
formbbs.insertBefore(newP, email.nextSibling);
} else {
const warning = document.getElementById('warning');
if(warning) {
warning.parentNode.removeChild(warning);
}
}
}).catch( e => console.log(e.message));
}
});
}
<?php
require 'function.php';
$input = json_decode(file_get_contents("php://input"), true);
if(!empty($input)) {
$dbh = dbConnect();
$sql = 'SELECT * FROM users WHERE email = ?';
$row = dbExec($dbh, $sql, $input['email']);
if($row > 0) {
echo json_encode([
'errorFlg' => true,
'msg' => '既に登録されています',
]);
} else {
echo json_encode([
'errorFlg' => false,
'msg' => '',
]);
}
exit();
}
<?php
function dbConnect() {
$dsn = 'mysql:dbname=test_bbs;host=localhost;charset=utf8';
$user = 'root';
$pass = 'root';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
];
try {
return new PDO($dsn, $user, $pass, $options);
} catch(PDOException $exception) {
print_r($exception->getMessage(), true);
die();
}
}
function dbExec($dbh, $sql,...$params) {
try {
if($dbh === null) {
return false;
}
if($params !== null && count($params)) {
$stmt = $dbh->prepare($sql);
foreach($params as $index => $param){
$stmt->bindValue($index+1, $param);
}
$stmt->execute();
return $stmt->rowCount();
}
return $dbh->exec($sql);
} catch(PDOException $exception) {
print_r($exception->getMessage(), true);
die();
}
}
実際の挙動が以下でございます。
データベースの中身はこちらです。
aaa@example.coまで打つと、ajax通信を行なっています。
その後、aaa@example.comまで打つと結果が返ってきています。
PHPの部分は割愛して、JavaScriptの部分を解説します。
- DOMContentLoadedで、DOMの読み込みが終わったらmain関数を呼び出します。
- email入力欄に入力があったらイベントを発火。
- まず、その入力された値がemailの形式かどうかチェックし、形式があっていれば次へ進みます。
- fetchの引数は2つ。
第1引数にurl、第2引数にオプションを指定します。
第2引数内もjson文字列で記述。
methodをPOST、bodyに送りたい内容をjson文字列に変換して送ります。
https://developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/fetch - fetchはPromiseを返すので、.thenで繋げて、responseを受け取ります。
しかし、このままだとresponseのbodyがReadableStreamとなっていて使えません。
さらに.thenを繋いで、response.json()で受け取ります。
ボディのテキストをJSON
として解釈した結果で解決する promise を返します。(https://developer.mozilla.org/ja/docs/Web/API/Body/json) - その前に、、、promiseは状態と結果を持っていると上のほうで説明していました。
fetch() promiseはサーバーと通信して、Responseが返ってきたらOKという状態を持ってしまいます。
fetch() が成功したかどうかの明確な判定をするには、プロミスが解決されて、Response.ok
プロパティが true になっているかを確認します。(https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch)
そのため、if文でresponse.okという条件をつけて、trueなら処理、falseならエラーをthrowして、最後の.catch()で取ってあげています。 - 最後に、jsonとして受け取ったものをHTMLに書き出します。