10
Jul
2020

Membuat Website Chat dengan Socket.io

Setelah sebelumnya kita membuat server untuk aplikasi chat, sekarang saatnya membuat clientnya. Dan di tutorial ini kita akan membuat client untuk platform web. Jika teman-teman ingin melihat penerapan untuk client di platform selain web bisa dilihat di Aplikasi Chat Multiplatform dengan Socket.io

Untuk web kita juga akan menggunakan Nodejs, jadi pastikan sudah tersintall di komputer teman-teman. Dan seperti pada server, versi yang digunakan untuk tutorial ini adalah versi 12.7.0.

1. Inisialisasi proyek dengan NPM init

Langkah-langkahnya sebagai berikut:

  1. Buat sebuah folder
  2. Buka cmd dan arahkan ke dalam folder yang baru saja dibuat
  3. Ketikkan npm init
  4. Isikan semua data yang diminta

2. Install library

Library yang dibutuhkan untuk web adalah sebagai berikut:

  • socket.io versi 2.3.0
  • socket.io-client versi 2.3.0
  • express versi 4.17.1
  • bootstrap versi 4.5.0
  • jquery versi 3.5.1

Install semua library di atas dengan mengetikkan npm install socket.io socket.io-client express bootstrap jquery di cmd yang tadi sudah dibuka.

3. Buat server

Walaupun di tutorial ini terkait dengan web yang berperan sebagai client dari server socket.io, tapi tetap memerlukan server. Bedanya dengan server chat socket.io di tutorial sebelumnya, server yang ini terdapat routing agar bisa membuka halaman webnya. Dan juga server ini listen ke port 80 beda dengan server chat socket.io yang listen ke port 3000.

Buat file index.js dan berikut kodenya:

const express = require('express');
const app = express();
const server = require('http').Server(app);

server.listen(80);

app.use('/node', express.static(__dirname + '/node_modules/bootstrap/dist/'));
app.use('/node', express.static(__dirname + '/node_modules/socket.io-client/dist/'));
app.use('/node', express.static(__dirname + '/node_modules/jquery/dist/'));

app.get('/', (req, res) => {
  res.sendFile(__dirname + '/index.html');
});

Penjelasan kode:

  • app.use(‘/node’, … – dengan kode tersebut kita bisa mengakses semua file di dalam direktori yang diberikan. Contoh untuk mengakses bootstrap.js, kita bisa mengaksesnya lewat http://localhost:80/node/bootstrap.js. Ini diperlukan karena nantinya akan digunakan di dalam halaman webnya.
  • app.get(‘/’, … – ini merupakan routing, dengan kode tersebut kita bisa mengakses index.html lewat http://localhost:80.

4. Buat tampilan halaman chat

Berikut adalah kode untuk tampilannya:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Web Chat dengan Socket.io</title>
    <link rel="stylesheet" href="/node/css/bootstrap.css">
    <style>
    .messages{
        overflow-y: auto;
        position: absolute;
        bottom: 0;
        width: 100%;
    }

    .message{
        display: none;
    }
    </style>
</head>
<body>
    <div class="container vh-100">
        <div class="row vh-100 align-items-center p-5">
            <div class="col-12 order-1 col-sm-4 order-sm-0 h-75">
                <div class="card h-100">
                    <div class="card-body d-flex flex-column align-items-stretch">
                        <p class="col-auto mb-0"><strong>Online</strong> <span id="onlineMember"></span></p>
                        <div>
                            <hr>
                        </div>
                        <div class="member col">

                        </div>
                        <div>
                            <hr>
                        </div>
                        <p class="col-auto mb-0">Status <strong><span id="currentStatus"></span></strong><button onclick="logout()" id="logout" class="btn btn-danger float-right d-none">Keluar</button></p>
                    </div>
                </div>
            </div>
            <div class="col-12 order-0 col-sm-8 order-sm-1 mb-3 mb-sm-0 h-75 d-flex flex-column">
                <div class="row flex-grow-1" style="overflow-y:auto">
                    <div class="col-12 pb-3 h-100">
                        <div class="card h-100">
                            <div class="card-body">
                                <div class="position-relative h-100">
                                    <div class="messages mh-100">
                                    </div>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div class="row">
                    <div class="col-12">
                        <div class="card h-100">
                            <div class="card-body">
                                <form id="formMessage" class="d-none">
                                    <div class="row">
                                        <div class="col">
                                            <input id="message" class="form-control" type="text" name="" value="" placeholder="Tuliskan pesan disini">
                                        </div>
                                        <div class="col-auto">
                                            <button class="btn btn-primary btn-connected-state">Kirim</button>
                                        </div>
                                    </div>
                                </form>
                                <form id="formAccount">
                                    <div class="row">
                                        <div class="col col-sm-6">
                                            <input id="accountName" class="form-control" type="text" name="" value="" placeholder="Masukkan nama">
                                        </div>
                                        <div class="col-auto">
                                            <button class="btn btn-primary btn-connected-state">Masuk</button>
                                        </div>
                                    </div>
                                </form>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Berikut tampilan yang dihasilkan

Penjelasan dari tampilan di atas adalah sebagai berikut:

  1. Menampilkan jumlah user yang sedang online
  2. Menampilkan daftar user yang sedang online
  3. Status dari socket.io, apakah Connected, Connecting atau Reconnecting. Dan juga nantinya jika user sudah masuk maka akan keluar tombol keluar
  4. Menampilkan percakapan
  5. Sebagai tempat untuk memasukkan nama sebelum login dan jika sudah login tampilan akan berganti menjadi tempat untuk memasukkan pesan

5. Uji koneksi ke server

Sebelum memasukan kode untuk sistem chatnya, alangkah baiknya kita coba dulu menghubungkan web chat ini ke server chat.

Tambahkan script dan kode berikut sebelum </body>

...
<script src="/node/jquery.js"></script>
<script src="/node/js/bootstrap.js"></script>
<script src="/node/socket.io.js"></script>
<script>
const socket = io.connect('http://localhost:3000');
socket.on('connect', () => {
    console.log('connected');
});
</script>
...

Kemudian jalankan server untuk web client dengan cara ketik node index.js di cmd. Dan pastikan juga server chat sudah dijalankan.

Jika berhasil terhubung ke server chat maka akan muncul tulisan connected di console di developer tools

6. Handle login dan tampilkan daftar pengguna

...    
let name = '';
let tempName = '';

$('#formAccount').submit(function(e){
    e.preventDefault();
    if ($('#accountName').val()=='') {
        return false;
    }
    tempName = $('#accountName').val() + '#' + Math.floor(Math.random() * 10000);
    socket.emit('login', tempName, loginCallback);
    return false;
});

function loginCallback(status){
    if (status=='success') {
        $('#logout').removeClass('d-none');
        $('#accountName').val('');
        $('#formMessage').removeClass('d-none');
        $('#formAccount').addClass('d-none');
        $('#logout').removeClass('d-none');
        name = tempName;
        tempName = '';
    }else{
        tempName = $('#accountName').val() + '#' + Math.floor(Math.random() * 10000);
        socket.emit('login', tempName, loginCallback);
    }
}

socket.on('users', function(users){
    $('.member').empty();
    for (var u of users) {
        $('.member').append($('<li>').text(u));
        updateUsersOnline();
    }
});

socket.on('newUser', function(newUser){
    $('.member').append($('<li>').text(newUser));
    updateUsersOnline();
});

function updateUsersOnline(){
    $('#onlineMember').text($('.member').children().length);
}
...

Penjelasan kodenya sebagai berikut:

  • let name dan let tempName – 2 variabel ini fungsinya untuk menyimpan nama. tempName digunakan untuk menyimpan nama sebelum callback success dari login. Jika callback return success maka nilai dari tempName dipindah ke name.
  • $(‘#formAccount’) – akan dipanggil ketika tombol Masuk ditekan.
  • $(‘#accountName’).val() + ‘#’ + Math.floor(Math.random() * 10000) – kode tersebut berfungsi untuk membuat nama unik. Kenapa perlu ditambahkan angka acak setelah tagar? Ini bertujuan untuk mengatasi pengguna yang mempunyai nama yang sama. Cara ini terinspirasi dari aplikasi chat Discord.
  • socket.emit(‘login’, – mengirim pesan login ke server dengan parameter tempName dan fungsi callback loginCallback.
  • function loginCallback – fungsi ini akan dipanggil setiap kali server mengirimkan balasan dari pesan login. Di dalam fungsi ini terdapat pengecekan apakah login success atau failed, jika success maka rubah tampilan untuk user yang sudah login dan juga simpan tempName ke name, jika balasan berupa failed atau selain success maka akan melakukan login lagi dengan nama yang kode digitnya sudah diacak lagi.
  • socket.on(‘users’, – kode ini akan dipanggil pertama kali setelah user connect ke server. Parameter yang dikirim melalui pesan ini berupa data user yang statusnya sedang online. Data tersebut di munculkan di bagian list data user. Jumlah data usernya juga di tampilkan melalui fungsi updateUsersOnline.
  • socket.on(‘newUser’, – akan dipanggil setiap kali ada user yang berhasil login ke server.
  • function updateUsersOnline() – fungsi ini berfungsi untuk memperbarui jumlah user.

7. Handle ketika user logout dan disconnect

...
socket.on('removeUser', function(removedMember){
    if (removedMember=='') {
        return;
    }
    if (removedMember == name) {
        $('#formMessage').addClass('d-none');
        $('#formAccount').removeClass('d-none');
        $('#logout').addClass('d-none');
    }
    $('.member li:contains("' + removedMember + '")').remove();
    updateUsersOnline();
});

function logout(){
    socket.emit('logout');
    if (name=='') {
        return;
    }
    $('.member li:contains("' + name + '")').remove();
    $('#logout').addClass('d-none');
    updateUsersOnline();
}
...
  • socket.on(‘removeUser’, – ini akan dipanggil ketika ada user yang disconnect atau logout.
  • function logout() – fungsi ini dipanggil ketika button keluar ditekan. Di dalam fungsi ini terdapat socket.emit(‘logout’) untuk mengirimkan pesan ke server bahwa user ini akan keluar.

8. Update status dan auto login setelah reconnect

...
updateStatus('Connecting');
socket.on('connect', () => {
    console.log('connected');
    updateStatus('Connected');
    if (name=='') {
        return;
    }
    socket.emit('login', name, loginCallback);
});
socket.on('disconnected', () => {
    updateStatus('Disconnected');
});
socket.on('reconnecting', () => {
    updateStatus('Connecting');
});
function updateStatus(status){
    $('#currentStatus').text(status);
    if (status==='Connected') {
        $('.btn-connected-state').prop('disabled', false);
    }else{
        $('.btn-connected-state').prop('disabled', true);
    }
}
...
  • Update fungsi socket.on(‘connect’, …, setiap kali tersambung ke server dan nama tidak kosong maka otomatis langsung login.
  • Update status setiap kali client connect, disconnected atau reconnecting.

9. Handle pertukaran pesan antar user

...
$('#formMessage').submit(function(e){
    e.preventDefault();
    if ($('#message').val()=='') {
        return false;
    }
    var msg = {
        id: Date.now() + name.split('#').pop(),
        message: $('#message').val(),
        name: name
    }
    socket.emit('newMessage', msg);
    $('#message').val('');
    return false;
});

socket.on('newMessage', function(msg){
    if (msg.name==name) {
        $('.messages').append($(`<div class="clearfix mb-1 message"><div class="float-right bg-primary text-white rounded p-2 text-right"><strong>${msg.name}</strong><br>${msg.message}</div></div>`));
    }else{
        $('.messages').append($(`<div class="clearfix mb-1 message"><div class="float-left bg-warning text-white rounded p-2 text-left"><strong>${msg.name}</strong><br>${msg.message}</div></div>`));
    }
    $('.message').fadeIn(500);
    $(".messages").animate({scrollTop: ($(".messages")[0].scrollHeight)}, 200);
});
...
  • $(‘#formMessage’) … – akan dipanggil ketika user menekan tombol kirim.
  • socket.on(‘newMessage’, – menerima parameter berupa pesan. Di dalam fungsi ini pesan terdapat kondisi jika nama dari pengirim pesan sama dengan nama user yang menerima, maka pesan akan ditampilkan di sebelah kanan dengan background warna biru. Jika nama beda maka akan ditampilkan di sebelah kiri dengan background warna kuning.

Berikut adalah hasil akhir dari tutorial ini

Untuk kodenya bisa dilihat di https://github.com/hendrawanwijaya/hendra-one-socket-io-web-chat.

Itulah tutorial tentang pembuatan web chat menggunakan socket.io. Semoga bisa bermanfaat untuk teman-teman semuanya. Jika ada pertanyaan, masukan atau koreksi, silahkan tuliskan komentar di bawah ya. Terima kasih.

Share

You may also like...