LoginSignup
0
1

More than 3 years have passed since last update.

node.jsとjQueryを使ってユーザー新規登録モーダルとログインモーダルを作ってみた

Last updated at Posted at 2021-03-06

画面遷移をせずにユーザー新規登録機能を作ってみました。
そこまで大した出来ではないです。
(実は理想としていたものより少々乖離しています。)

node.jsやjQueryの導入はこちらでは省いています。
また、新規登録、ログインモーダル以外の要素もありません。ご了承ください。

node.jsのバージョンは v14.15.4 です。
また、MySQLを使用しています。

1.必要なものをインストール

ターミナル
$ npm install express  //expressをインストールします
$ npm install mysql  //mysqlと接続できます
$ npm install express-session   //登録機能です
$ npm install bcrypt  //パスワードをハッシュ化してくれる機能です

これでインストールは以上です。

今回、ユーザー新規登録には、
username , email , password
の情報が必須となる設定にしています。

2.ルーティングのコードを書いていく

ディレクトリ構造は以下のようになっております
(node_modulesなどは省略しています。)

registation_app/
├ public/
│  ├ css/
│  │  └style.css/
│  ├ script.js/
│  └ validate.js/
├ views/
│  ├ log_in.ejs/
│  ├ sign_up.ejs/
│  ├ top.ejs/
│  └ uniq_error.ejs/
└ app.js/

app.js

// インストールしたものを適用させます
const express = require('express');
const mysql = require('mysql');
const session = require('express-session');
const app = express();
const bcrypt = require('bcrypt');

app.use(express.static('public'));
app.use(express.urlencoded({extended: false}));

// DBと接続します
const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'パスワードを入力',
  database: 'DB名を入力'
});

// トップ画面のルーティング
app.get('/', (req, res) => {
  res.render('top.ejs');
});

// 重複するメールアドレスがある場合の画面遷移
app.get('/uniq_error',(req,res) =>{
  res.render('uniq_error.ejs');
});

// 新規登録のルーティング
app.post('/sign_up',
(req, res, next) => {
  const email = req.body.email;

  connection.query(
    'SELECT * FROM users WHERE email = ?',
    [email],
    (error, results) => {
      if (results.length > 0) {
        res.render('uniq_error.ejs');
      } else {
        next();
      }
    }
  );

},

(req,res) => {
  bcrypt.hash(password,10,(error,hash) => {
    connection.query(
      'INSERT INTO users (username, email, password) VALUES (?, ?, ?)',
      [username, email, hash],
      (error, results) => {
        req.session.userId = results.insertId;
        req.session.username = username;
        res.redirect('/');
      }
    );
  });
});

// ログインのルーティング
app.post('/log_in', (req, res) => {
  const email = req.body.email;
  connection.query(
    'SELECT * FROM users WHERE email = ?',
    [email],
    (error, results) => {
      if (results.length > 0) {
        const plain = req.body.password;
        const hash = results[0].password;
        bcrypt.compare(plain,hash,(error,isEqual) => {
          if(isEqual){
          req.session.userId = results[0].id;
            req.session.username = results[0].username;
            res.redirect('/');
          } else {
            res.redirect('/');
          }
        });
      } else {
        res.redirect('/');
      }
    }
  );
});

// ログアウトのルーティング
app.get('/log_out', (req, res) => {
  req.session.destroy(error => {
    res.redirect('/');
  });
});

// ローカルホスト3000に接続
app.listen(3000);
});

3.トップ画面などのコーディング

top.ejs
<!DOCTYPE html>
<html>
  <head>
<meta charset="utf-8">
<title>registration_APP</title>
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script type="text/javascript" src="script.js"></script>
<script type="text/javascript" src="validate.js"></script>
  </head>
  <body>
<header>
  <div class="header-wrapper" >
    <a href="/" class="header-logo-left">registration_APP</a>
    <% if (locals.isLoggedIn) { %>
      <a class="header-logo-right" href="/log_out">ログアウト</a>
    <% } else { %>
    <div>
      <a class="header-logo-right login-show">ログイン</a>
      <a class="header-logo-right signup-show">新規登録</a>
      <% } %>
  </div>
  </div>
</header>
    <%- include('sign_up'); %>
    <%- include('log_in'); %>
  </body>
</html>

<%- include('sign_up'); %>で新規登録モーダル
<%- include('log_in'); %>でログインモーダルを呼び出します。

ある特定のページでのみモーダルを出現させるのであればこの記述をする必要はありませんが、
複数のページでモーダルを出したい場合、このようにすると使いまわせるので便利です。

sign_up.ejs
//新規登録モーダル

<div class="signup-modal-wrapper" id="signup-modal">
  <div class="modal">
    <div id="signup-close-modal">
      <i class="fa fa-2x fa-times"></i>
    </div>
    <div id="signup-form">
      <h2>新規登録</h2>
      <form action="/sign_up" method="post" id="sign_up-form">
        <p class="error-message" id="sign_up-username-error-message"></p>
        <input class="form-control" type="text" placeholder="ユーザー名" name="username" id="sign_up-username">
        <p class="error-message" id="sign_up-email-error-message"></p>
        <input class="form-control" type="text" placeholder="メールアドレス" name="email" id="sign_up-email">
        <p class="error-message" id="sign_up-password-error-message"></p>
        <input class="form-control" type="password" placeholder="パスワード" name="password" id="sign_up-password">
        <input id="submit-btn" type="submit" value="登録する">
      </form>
    </div>
  </div>
</div>
log_in.ejs
//ログインモーダル

<div class="login-modal-wrapper" id="login-modal">
  <div class="modal">
    <div id="login-close-modal">
      <i class="fa fa-2x fa-times"></i>
    </div>
    <div id="login-form">
      <h2>ログイン</h2>
      <form action="/log_in" method="post">
        <input class="form-control" type="text" placeholder="メールアドレス" name="email">
        <input class="form-control" type="password" placeholder="パスワード" name="password">
        <input id="login-btn" type="submit" value="ログインする">
      </form>
    </div>
  </div>
</div>

これでトップ画面で二種類のモーダルをだせるようになりました。
(この段階では二種類のモーダルは現れた状態になっています。)
この後CSSを使ってモーダルを隠し、jQueryで表示させるアクションを作成します。

4.CSSをコーディング

CSSは全て書くととても長くなるので、必要最低限のところだけ
モーダルの大きさや文字の大きさ、背景色などはお好みで。

style.css

/* ヘッダーの『新規登録』『ログイン』部分 */
.header-logo-right {
  display: inline;
}

.header-logo-right:hover {
  cursor: pointer;
}


/* モーダル部分 */
.signup-modal-wrapper,.login-modal-wrapper{
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 100;
  display: none;
}

.modal {
  position: absolute;
  top: 20%;
  left: 34%;
  background-color: #e6ecf0;
  padding: 20px 0 40px;
  border-radius: 10px;
  width: 450px;
  height: auto;
  text-align: center;
}

.fa-times {
  position: absolute;
  top: 12px;
  right: 12px;
  color: rgba(128, 128, 128, 0.46);
  cursor: pointer;
}

#signup-form,#login-form{
  width: 100%;
}

これで新規登録、ログインボタンにカーソルを合わせるとポインタが変わります
さらにモーダル部分は隠れました。
それではjQueryを使ってモーダルが現れるように処理しましょう。

5.Jqueryをコーディング

script.js
$(function(){
  $('.signup-show').click(function(){
    $('#signup-modal').fadeIn();
  });

  $('#signup-close-modal').click(function(){
    $('#signup-modal').fadeOut();
  });
});

$(function(){
  $('.login-show').click(function(){
    $('#login-modal').fadeIn();
  });

  $('#login-close-modal').click(function(){
    $('#login-modal').fadeOut();
  });
});

これで、『新規登録』を押すと『新規登録モーダル』が
『ログイン』を押すと『ログインモーダル』が出るようになりました。

これで、新規登録並びにログインモーダルが完成です。

・・・と言いたい所さんですが、このままだと空白でも登録ができてしまいます。
と言うわけでバリデーションをかけていきましょう

6.バリデーションをかける

今回はjQuery側でバリデーションチェックをします。
挙動としては、入力に問題がある場合、送信はできず問題箇所にエラー文が出るようにします。

validate.js
$(function() {
  $('#sign_up-form').submit(function(){
    var usernameValue = $('#sign_up-username').val();
    var emailValue = $('#sign_up-email').val();
    var passwordValue = $('#sign_up-password').val();
    var errorCount = 0;

    if(usernameValue === ""){
      $('#sign_up-username-error-message').text('ニックネームを入力してください');
      errorCount += 1;
    } else {
      $('#sign_up-username-error-message').text('');
    }

    if(emailValue === ""){
      $('#sign_up-email-error-message').text('メールアドレスを入力してください');
      errorCount += 1;
    } else if(!emailValue.match(/^[a-zA-Z0-9_.+-]+@([a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]*\.)+[a-zA-Z]{2,}$/)){
      $('#sign_up-email-error-message').text('メールアドレスが正しくありません');
      errorCount += 1;
    } else {
      $('#sign_up-email-error-message').text('');
    }

    if(passwordValue === ""){
      $('#sign_up-password-error-message').text('パスワードを入力してください');
      errorCount += 1;
    } else if(!passwordValue.match(/^(?=.*[a-zA-Z])(?=.*[0-9])[0-9a-zA-Z]{6,}$/) ){
      $('#sign_up-password-error-message').text('パスワードは半角英数字6文字以上が必要です');
      errorCount += 1;
    } else {
      $('#sign_up-password-error-message').text('');
    }

    if(errorCount !== 0){
      return false;
    }
  });
});

これでバリデーションチェックができます。
解説としてはerrorCountを0と最初に定義し、問題箇所1つにつきerrorCountが1上昇していきます。
そして最後、errorCountが0ではない場合送信できないように設定してあります。
そして全てのチェックが通ればerrorCountは0なので送信し、ユーザー登録できる。
と言う仕掛けになっております。

これにて完成です。
と思ったら間違えです。
このままだと同じメールアドレスが登録できてしまいます。

ここから先が私の作りたかったモーダルとの理想と実力の無さが出た場所でした。

7.実現したかった内容

ここで同じアドレスが登録されている場合にもerrorCountを1上昇させる処理をしたかったのですが、
ajax通信が何をやってもうまくいきませんでした。
jQuery単体では厳しいようで、PHPが必要なようです。
(jQueryだけでどうにかならないか色々勉強中です。)

仕方ないので、node.js側で同じメールアドレスがある場合は弾き、アラートを出す妥協案にしましたが、これまた失敗。
理由はnode.jsではalertメソッドが使えないようです。

8.苦し紛れに出した自分なりの答え

アラートが出せずにしばらく考え、出した結論が
『既に登録されているメールアドレスがあるため登録できませんでした』

と書かれたページへ遷移することでした。
コードで言うと、最初のapp.jsに既に記述してありますが、再び記述すると

javascript;app.js
app.post('/sign_up',
(req, res, next) => {
  const email = req.body.email;

  connection.query(
    'SELECT * FROM users WHERE email = ?',
    [email],
    (error, results) => {
      if (results.length > 0) {
        res.render('uniq_error.ejs');
      } else {
        next();
      }
    }
  );

こちらの部分になります。
これで重複するメールアドレスの場合はuniq_error.ejsに遷移します。

ちなみにuniq_error.ejsには
『既に登録されているメールアドレスがあるため登録できませんでした』
の文字しかありません。

9.終わりに

バリデーションチェックまでは苦戦しながらも進められたのですが、メールアドレスの重複チェックで躓き、数十時間もがき苦しみました。

まだまだ理解が足りない証拠ですね。
PHPの知識もそのうち入れたいと思います。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1