node.jsを触るために簡単なチャットシステムを作る（メッセージ送信編）

Node.js を触ってみたいと思ったので、備忘録も兼ねて以下に記します。
よりよい方法やバグ等ございましたら、アドバイスいただけると光栄です。

今回は「メッセージ送信編」ということで、クライアントからサーバーへのメッセージの送信の処理を作成します。

※前回 [node.jsを触るために簡単なチャットシステムを作る（サーバー接続編）](https://qiita.com/sunnyG/items/2e7b9d89acfc2b0938e4) という表題で、サーバー接続の処理を作成していますので、まだな方はこちらを参照ください。

# クライアントからサーバーへメッセージを送信する

## メッセージ入力フォームを作成

`/public/index.html` に、以下のメッセージ入力フォームを追加します。

```html:index.html
<form action="">
    <input type="text" id="input_message" autocomplete="off" />
    <button type="submit">Send</button>
</form>
```

`index.html` 全体としては、以下のようになります。

```html:index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>mychat</title>
</head>
<body>
    <h1>node.js を触ってみた</h1>
    <form action="">
        <input type="text" id="input_message" autocomplete="off" />
        <button type="submit">Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="client.js"></script>
</body>
</html>
```

## クライアント側の処理

`/public/client.js` の末尾に、下記のようなSendボタンを押したときの処理を追加します。

```js:client.js
// 「Send」ボタンを押したときの処理
$('form').submit(() => {
    const $inp = $('#input_message');
    const text = $inp.val();

    console.log('#input_message :', text);

    if (text) {
        // サーバーに、イベント名 'new message' で入力テキストを送信
        socket.emit('new message', text);
        // テキストボックスを空に
        $inp.val('');
    }
    // フォーム送信はしない
    return false;
});
```

`/public/client.js` 全体としては、以下のようになります。

```js:client.js
'use strict';

// クライアントからサーバーへの接続要求
const socket = io.connect();

// 接続時の処理
socket.on('connect', () => {
    console.log('connect');
});

// 「Send」ボタンを押したときの処理
$('form').submit(() => {
    const $inp = $('#input_message');
    const text = $inp.val();

    console.log('#input_message :', text);

    if (text) {
        // サーバーに、イベント名 'new message' で入力テキストを送信
        socket.emit('new message', text);
        // テキストボックスを空に
        $inp.val('');
    }
    // フォーム送信はしない
    return false;
});
```

## サーバー側の処理

`server.js` の「接続時の処理」の中に、下記処理を追加します。

```js:server.js
// 新しいメッセージ受信時の処理
socket.on('new message', (strMessage) => {
    console.log('new message', strMessage);
});
```

`server.js` 全体としては、以下のようになります。

```js:server.js
'use strict';

// モジュール
const http     = require('http');
const express  = require('express');
const socketIO = require('socket.io');
const moment   = require('moment');

// オブジェクト
const app    = express();
const server = http.Server(app);
const io     = socketIO(server);

// 定数
const PORT = process.env.PORT || 3000;

// グローバル変数
let iCountUser = 0; // ユーザー数

// 接続時の処理
io.on('connection', (socket) => {
    console.log('connection');
 
    // 切断時の処理
    socket.on('disconnect', () => {
        console.log('disconnect');
    });

    // 新しいメッセージ受信時の処理
    socket.on('new message', (strMessage) => {
        console.log('new message', strMessage);
    });
});

// 公開フォルダの指定
app.use(express.static(__dirname + '/public'));

// サーバーの起動
server.listen(PORT, () => {
    console.log('server starts on port: %d', PORT);
});
```

## 動作を確認する

サーバーを立ち上げた状態で、
http://localhost:3000 にアクセスします。

「aaa」と「あああ」というメッセージをフォームに入力し、「Send」ボタンを押します。
Google Chrome のデベロッパーツールの Console に、`connect`に続いて、
`#input_message : aaa`
`#input_message : あああ`
と表示されます。

下記のようにサーバー側で `connection` に続いて、
`new message aaa`
`new message あああ`
と表示されれば完了です。

```bash
node server.js
server starts on port: 3000
connection
new message aaa
new message あああ
```

# サーバーからクライアントへメッセージを拡散する

## サーバー側の処理

`server.js` の「接続時の処理」の中に、下記処理を追加します。

```js:server.js
// 送信元含む全員に送信
io.emit('spread message', strMessage);
```

`server.js` 全体としては、以下のようになります。

```js:server.js
'use strict';

// モジュール
const http     = require('http');
const express  = require('express');
const socketIO = require('socket.io');
const moment   = require('moment');

// オブジェクト
const app    = express();
const server = http.Server(app);
const io     = socketIO(server);

// 定数
const PORT = process.env.PORT || 3000;

// グローバル変数
let iCountUser = 0; // ユーザー数

// 接続時の処理
io.on('connection', (socket) => {
    console.log('connection');
 
    // 切断時の処理
    socket.on('disconnect', () => {
        console.log('disconnect');
    });

    // 新しいメッセージ受信時の処理
    socket.on('new message', (strMessage) => {
        console.log('new message', strMessage);

        // 送信元含む全員に送信
        io.emit('spread message', strMessage);
    });
});

// 公開フォルダの指定
app.use(express.static(__dirname + '/public'));

// サーバーの起動
server.listen(PORT, () => {
    console.log('server starts on port: %d', PORT);
});
```

## クライアント側の処理

`/public/client.js` の末尾に、下記のようなSendボタンを押したときの処理を追加します。

```js:client.js
// サーバーからのメッセージ拡散に対する処理
socket.on('spread message', (strMessage) => {
    console.log('spread message :', strMessage);

    // 拡散されたメッセージをメッセージリストに追加
    const li_element = $('<li>').text(strMessage);
    $('#message_list').prepend(li_element);
});
```

`/public/client.js` 全体としては、以下のようになります。

```js:client.js
'use strict';

// クライアントからサーバーへの接続要求
const socket = io.connect();

// 接続時の処理
socket.on('connect', () => {
    console.log('connect');
});

// 「Send」ボタンを押したときの処理
$('form').submit(() => {
    const $inp = $('#input_message');
    const text = $inp.val();

    console.log('#input_message :', text);

    if (text) {
        // サーバーに、イベント名 'new message' で入力テキストを送信
        socket.emit('new message', text);
        // テキストボックスを空に
        $inp.val('');
    }
    // フォーム送信はしない
    return false;
});

// サーバーからのメッセージ拡散に対する処理
socket.on('spread message', (strMessage) => {
    console.log('spread message :', strMessage);

    // 拡散されたメッセージをメッセージリストに追加
    $('#message_list').prepend($('<li>').text(strMessage));
});
```

## メッセージをビュー側に表示

`/public/index.html` のメッセージ入力フォームの下に、以下のメッセージリストを追加します。

```html:index.html
<ul id="message_list"></ul>
```

`index.html` 全体としては、以下のようになります。

```html:index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>mychat</title>
</head>
<body>
    <h1>node.js を触ってみた</h1>
    <form action="">
        <input type="text" id="input_message" autocomplete="off" />
        <button type="submit">Send</button>
    </form>
    <ul id="message_list"></ul>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script src="client.js"></script>
</body>
</html>
```

## 動作を確認する

### メッセージの表示

サーバーを立ち上げた状態で、
http://localhost:3000 にアクセスします。

「aaa」と「あああ」というメッセージをフォームに入力し、「Send」ボタンを押します。

送信したメッセージが、リスト表示されます。

### 別ブラウザでもメッセージを表示

ブラウザを別に立ち上げ、
http://localhost:3000 にアクセスします。

「bbb」と「いいい」というメッセージをフォームに入力し、「Send」ボタンを押します。

送信したメッセージが、両方のブラウザに、即座に、リスト表示されれば完了です。


# 最後に

今回作成する機能としては以上となります。

ここで作成した機能をベースに、
以下のような機能や他にも自分で思いついた機能などを追加してみるのも良い学習になると思います。

+ メッセージに時刻を表示
+ メッセージに発信者名を表示
+ ユーザーの入室、退室を表示

ソースコードは以下に載せていますので、よろしければ参照ください。
https://github.com/genki-sano/express-socketio-chat

# 関連記事

+ [node.jsを触るために簡単なチャットシステムを作る：環境構築編](https://qiita.com/sunnyG/items/60b1968cd4cc390ff804)
+ [node.jsを触るために簡単なチャットシステムを作る：サーバー接続編](https://qiita.com/sunnyG/items/2e7b9d89acfc2b0938e4)
+ [node.jsを触るために簡単なチャットシステムを作る：メッセージ送信編](https://qiita.com/sunnyG/items/859aed447fa88665e601)