Belajar Membuat Web Menggunakan Framework Express JS (Part 8) - CRUDPRO

Belajar Membuat Web Menggunakan Framework Express JS (Part 8)


Upload File Pada Framework Express JS - Pada tutorial sebelumnya kita sudah belajar Membuat CRUD (Create Read Update Delete) Pada Framework Express JS, nah sekarang kita langsung saja ke topik pembahasannya yaitu membuat fitur upload pada framework Express JS

Tambahkan 1 field dengan nama avatar pada tabel users, didalam file migration user seperti ini

'use strict';

module.exports = {
    up: (queryInterface, Sequelize) => {
        return queryInterface.createTable('Users', {
            id: {
                allowNull: false,
                autoIncrement: true,
                primaryKey: true,
                type: Sequelize.INTEGER
            },
            username : {
                type: Sequelize.STRING,
                unique : true 
            },
            password : {
                type: Sequelize.STRING
            },
            email: {
                type: Sequelize.STRING,
                unique : true 
            },
            avatar : {
                type : Sequelize.STRING,
                allowNull: true,
            },
            createdAt: {
                allowNull: true,
                type: Sequelize.DATE
            },
            updatedAt: {
                allowNull: true,
                type: Sequelize.DATE
            }
        });
    },

    down: (queryInterface, Sequelize) => {
        return queryInterface.dropTable('Users');
    }
};

Lalu jalankan perintah commands di bawah ini

$ sequelize db:migrate:undo:all
$ sequelize db:migrate
$ sequelize db:seed:all

Kemudian buat 1 menu Settings pada halaman dashboard index seperti dibawah ini

div.col-md-3
            a(href=`${route.dashboards.pages.setting.index}`)
                .card.x-pointer.menu
                    .card-body
                        center
                            i.fa.fa-cog.fa-5(style="font-size:5em;")
                            p
                            h3
                                b SETTINGS

Lalu tambahkan route settings di dalam file routes/routes.js & routes/web.js

routes.js

const dashboardPrefix = '/dashboards';

module.exports = function() {

    return {
        index : '/',
        auth : {
            login : '/auth',
            logout : '/auth/logout'
        },
        dashboards : {
            index : dashboardPrefix,
            pages : {
                user : {
                    index : dashboardPrefix + '/page/users',
                    create : dashboardPrefix + '/page/users/create',
                    store : dashboardPrefix + '/page/users/store',
                    edit : dashboardPrefix + '/page/users/edit',
                    update : dashboardPrefix + '/page/users/update',
                    destroy : dashboardPrefix + '/page/users/destroy',
                },
                setting : {
                    index : dashboardPrefix + '/page/setting',
                    update : dashboardPrefix + '/page/setting/update',
                }
            }
        }
    };
}

web.js

'use-strict'

const   express = require('express'),
        router = express.Router(),
        authController = require('../controllers/authController'),
        dashboardController = require('../controllers/dashboard/dashboardController'),
        settingController = require('../controllers/dashboard/settingController'),
        userController = require('../controllers/dashboard/userController'),
        { check } = require('express-validator'),
        routes = require('../routes/routes'),
        routePrefix = routes()

router

    /*
    * Index Route
    */
    .get(routePrefix.index, function(req, res, next) {
        res.render('index', { title : process.env.NODE_APP_NAME })
    })

    /*
    * Auth Routes
    */
    .get(routePrefix.auth.login, authController.index)
    .post(routePrefix.auth.login, [
        check('email','Email is required.').not().isEmpty(),
        check('email','Invalid email format.').isEmail(),
        check('password', 'Password is required.').not().isEmpty(),
    ], authController.login)
    .get(routePrefix.auth.logout, authController.logout)

    /*
    * Dashboard Routes
    * ===============================================
    */
    .get(routePrefix.dashboards.index, dashboardController.index)

    /*
    * Setting Routes
    * ===============================================
    */
    .get(routePrefix.dashboards.pages.setting.index, settingController.index)
    .post(routePrefix.dashboards.pages.setting.update, settingController.update)

    /*
    * Dashboard Routes
    * ===============================================
    * Page Name : users
    */
    .get(routePrefix.dashboards.pages.user.index, userController.index)
    .get(routePrefix.dashboards.pages.user.create, userController.create)
    .post(routePrefix.dashboards.pages.user.store, [
        check('username','The username is required.').not().isEmpty(),
        check('email','The email is required.').not().isEmpty(),
        check('email','Invalid email format.').isEmail(),
        check('password', 'Password is required.').not().isEmpty(),
    ], userController.store)
    .get(routePrefix.dashboards.pages.user.edit + '/:id', userController.edit)
    .put(routePrefix.dashboards.pages.user.update + '/:id', [
        check('username','The username is required.').not().isEmpty(),
        check('email','The email is required.').not().isEmpty(),
        check('email','Invalid email format.').isEmail(),
    ], userController.update)
    .get(routePrefix.dashboards.pages.user.destroy + '/:id', userController.destroy)

module.exports = router;

Setelah itu kita buat 1 file controller di dalam folder controllers/dashboard dengan nama settingController.js

exports.index = function(req, res, next) {
    res.render('dashboard/setting/index', {
        title : 'Setting'
    });
}

exports.update = function(req, res, next) {
    /*
    * Check image file is required
    */
    if(!req.files || Object.keys(req.files).length === 0) {
        return res.json({
            error   : true,
            message : 'Image file is required.'
        });
    }

    let fileImage = req.files.avatar;
    let fileName = fileImage.name;
    let fileMimetype = fileImage.mimetype;
    let currentSession = JSON.parse(req.session.userdata);

    if(fileMimetype != 'image/jpeg') {
        if(fileMimetype != 'image/png') {
            return res.json({
                error   : true,
                message : 'Image file not allowed to upload.'
            });
        }
    }


    fileImage.mv(process.env.NODE_AVATAR_PATH + fileName, function(err) {
        if(err) {
            return res.json({
                error   : true,
                message : err
            });
        }
        res.json({
            error   : false,
            message : 'Your article was created.'
        });
    });

}

Yang terakhir buat viewnya di dalam folder views/dasboard/setting dan beri nama index.pug, berikut adalah source code nya

extends ../layout

block stylesheets
    link(rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/bs4/dt-1.10.20/datatables.min.css")

block content

    div.row
        div.col-md-12
            div.card
                div.card-body
                    nav
                        div.nav.nav-tabs.tabs-alt#nav-tab(role="tablist")
                            a.nav-item.nav-link.mr-4.active#nav-avatar-tab(data-toggle="tab" href="#nav-avatar" role="tab" aria-controls="nav-avatar" aria-selected="true") Avatar
                    div.tab-content
                        div.tab-pane.fade.show.active#nav-avatar(role="tabpanel" aria-labelledby="nav-profile-tab")
                            div.pb-3
                            img.rounded.float-left.avatar-image(src="data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22200%22%20height%3D%22200%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20200%20200%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_170b7929ca4%20text%20%7B%20fill%3Argba(255%2C255%2C255%2C.75)%3Bfont-weight%3Anormal%3Bfont-family%3AHelvetica%2C%20monospace%3Bfont-size%3A10pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_170b7929ca4%22%3E%3Crect%20width%3D%22200%22%20height%3D%22200%22%20fill%3D%22%23777%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2270.79166603088379%22%20y%3D%22105.1%22%3E200x200%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E" style="cursor:pointer;" onclick="changeAvatar()")

                            form.avatarForm(enctype="multipart/form-data")
                                input(type="file" name="avatar" id="userAvatar" style="display:none;" onchange="readUrl(this)")


block scripts
    script.

        /*
        * Change Avatar
        */
        function changeAvatar() {
            jQuery('#userAvatar').trigger('click');
        }

        /*
        * Preview Image
        */
        function readUrl(input) {
            if(input.files && input.files[0]) {

                var reader = new FileReader();
                var file = input.files[0];

                if(jQuery.inArray(file.type, ['image/png','image/jpg','image/jpeg','image/gif']) >= 0) {
                    reader.onload = function (e) {
                        jQuery('.avatar-image').attr('src', e.target.result);
                    };
                    reader.readAsDataURL(input.files[0]);
                    uploadAvatar(input.files[0]);
                } else {
                    nativeToast({
                        message: 'Your file is not allowed to upload.',
                        position: 'top',
                    });
                }
            }
        }

        /*
        * Do upload
        */
        function uploadAvatar(param) {

            var formData = new FormData();
            formData.append('avatar', param, param.name);

            jQuery.ajax({
                method: 'post',
                url : '#{route.dashboards.pages.setting.update}',
                processData : false,
                contentType : false,
                cache : false,
                data : formData,
                beforeSend : function() {
                    nativeToast({
                        message: "Uploading ...",
                        position: 'top',
                    });
                },
                success : function(response) {
                },
                error : function(response) {
                    nativeToast({
                        message: response.responseJSON.message,
                        position: 'top',
                    });
                }
            });
        }

Berikut adalah hasilnya :