AJAX Form Menggunakan VueJS di Laravel


Berbeda dengan jQuery yang menyertakan HTTP Client di paket instalasinya, VueJS tidak menyediakan fitur serupa. Itulah kenapa, Laravel menambahkan paket lainnya untuk mendukung proses komunikasi data via AJAX, Axios namanya. Khusus di versi 5.3 ke bawah, Laravel menggunaan Vue Resource sebagai rekomendasi librari HTTP client.

Paket instalasi dan konfigurasi JavaScript dapat dilihat pada berkas resources/assets/js/bootstrap.js.
Berbekal dengan Axios dan VueJS, kita bisa membuat AJAX form yang interaktif serta proses yang lebih cepat di klien. Berikut penjabaran dan langkah pembuatannya.

Contoh Kasus

Tutorial kali ini akan memberikan contoh kasus formulir kontak. Di mana, formulir yang sudah diisi akan divalidasi di sisi server dengan request AJAX. Apabila data tidak valid, maka akan menampilkan pesan kesalahan. Pun begitu sebaliknya, apabila sukses akan menampilkan pesan kalau email berhasil dikirim.

Khusus bagian kirim email dan proses manipulasi datanya tidak akan dijabarkan pada contoh aplikasi maupun tulisan ini. Fokusnya adalah mengirim data dan mendapatkan responsnya melalui AJAX menggunakan VueJS.

Membuat Controller dan Route

Buat controller baru dengan nama MessageController . Controller ini akan memiliki dua buah method, yaitu form() dan method send().

$ php artisan make:controller MessageController

Method form() berfungsi untuk memuat view yang akan ditampilkan ke pengguna. Sedangkan method send() berfungsi untuk memvalidasi data, memproses data, kemudian mengambalikan respon untuk diproses di klien.

Skrip lengkap contoh controller tersebut dapat dilihat pada skrip di bawah.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MessageController extends Controller
{
    public function form()
    {
    	return view('contact.form');
    }

    public function send(Request $request)
    {
    	// validate request
    	$this->validate($request, [
    		'name' => 'required|string|max:50',
    		'email' => 'required|email|max:150',
    		'message' => 'required|string|max:2000'
    	]);

    	// do something here...


    	// return as JSON
    	return response()->json([
    		'success' => true,
    		'message' => 'Pesan berhasil dikirim.'
    	]);
    }
}

Dalam method send() ditambahkan skrip validasi menggunakan Controller Helper. Jika validasi berhasil, akan memroses data dan mengembalikan respons dalam bentuk JSON.

Jangan lupa, untuk menambahkan dua buah route dengan HTTP Verb yang berbeda pada kedua method tersebut.

// contact routes
Route::get('contact', 'MessageController@form')->name('contact.form');
Route::post('send', 'MessageController@send')->name('contact.send');

Membuat Komponen VueJS

Langkah selanjutnya adalah membuat tampilan berupa formulir yang berisi 3 atribut, ialah nama, email, dan pesan. Khusus pada bagian formulir ini, kita tidak langsung membuatnya dalam berkas Blade, namun memasukkannya dan menjadikannya sebagai komponen VueJS.

Di dokumentasi, sudah dicontohkan membuat komponen VueJS di Laravel.

Komponen VueJS

Buat berkas baru dengan nama Contact-form.vue dalam direktori resources/assets/js/components. Kita mulai dari membuat formulirnya, kemudian menambahkan skrip logika pada berkas yang sama. Jangan lupa, tag HTML dalam komponen VueJS harus diapit dalam tag <template>.

<template>
  <form @submit.prevent="send" method="post" action="/send">

    <div v-if="success" class="alert alert-success">
      Terima kasih. Pesan berhasil dikirim.
    </div>

    <div class="form-group">
      <label>Nama Lengkap</label>
      <input v-model="state.name" type="text" name="name" class="form-control">
      <span class="label label-danger">{{ error(errors.name) }}</span>
    </div>

    <div class="form-group">
      <label>Pos-el</label>
      <input v-model="state.email" type="email" name="email" class="form-control">
      <span class="label label-danger">{{ error(errors.email) }}</span>
    </div>

    <div class="form-group">
      <label>Pesan</label>
      <textarea v-model="state.message" name="message" class="form-control"></textarea>
      <span class="label label-danger">{{ error(errors.message) }}</span>
    </div>

    <div class="form-group">
      <button class="btn btn-primary" type="submit">
        Kirim Pesan
      </button>
    </div>
    
  </form>	
</template>

<script>
  export default {
    data() {
      return {
        success: false,
        errors: [],
        state: {
          name: '',
          email: '',
          message: ''
        }
      }
    },

    methods: {

      send(e) {
        axios.post(e.target.action, this.state).then(response => {
          this.success = response.data.success;
          
          if(response.data.success == true) {
            this.errors = [];

            this.state = {
              name: '',
              email: '',
              message: ''
            }
          }
        }).catch(error => {
          if (error.response.status == 422) {
            this.errors = error.response.data;
          }
        })
      },

      error(field) {
        return _.head(field);
      }
    }
  }
</script>

Sedikit penjelasan. Pada tag <form>, ditambahkan event submit yang akan memanggil method send() pada instance Vue. Selain itu, event submit juga di-chain dengan method prevent untuk menghindari formulir dikirim melalui peramban (browser).

Daftarkan komponen Vue tersebut pada berkas resources/assets/js/app.js dengan nenambahkan potongan skrip di bawah.

Vue.component('contact-form', require('./components/Contact-form.vue'));

Dengan mendaftarkan komponen tersebut, kita bisa menggunakan tag <contact-form> pada Blade untuk menampilkan formulir kontak. Oh ya, sebelum menggunakan, pastikan kalian mengkompilasi ulang asset di Laravel dengan perintah berikut.

$ npm run production

// atau

$ npm run watch

Membuat View

Sebelum membuat view partial, kita bisa memanfaatkan template bawaan Laravel dengan menjalankan perintah di bawah.

$ php artisan make:auth

Dari perintah tersebut, tak hanya auth yang dapat kita gunakan, namun base template yang terletak pada direktori resources/views/layouts.

Buat view baru dengan nama form.blade.php dalam direktori resources/views/contact. Tambahkan beberapa tag sehingga membentuk tampilan sesuai dengan keinginan. Contoh lengkapnya dapat dilihat pada media di bawah. Jangan lupa meletakkan tag <contact-form> pada posisi yang tepat.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Formulir Kontak</div>

                <div class="panel-body">
                    <contact-form></contact-form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Dalam skrip, kita mendefinisikan dua buat variabel, yang pertama dengan nama errors dengan tipe data array dan nilainya kosong. Sedangkan variabel selanjutnya dengan nama state merupakan model dan nilai awal pada ketiga atribut formulir di atas.

Terdapat satu method yang didefinisikan pada skrip, yaitu send(). Method ini berfungsi untuk mengirim data dari formulir ke server, kemudian mengambil dan memroses responsnya.

Dalam Axios, untuk HTTP status di rentang 2xx (misal 200), maka dianggap berhasil. Sedangkan di rentang 5xx (500) dan 4xx (403, 404, dst) maka dianggap gagal.

Dalam Laravel, validasi yang gagal akan mengembalikan HTTP status 422 — Unprocessable Entity — yang merupakan respons gagal apabila di proses oleh Axios. Kontennya sendiri berisi data JSON daftar formulir yang belum valid.

{
   "name":[
      "The name field is required."
   ],
   "email":[
      "The email field is required."
   ],
   "message":[
      "The message field is required."
   ]
}

Untuk menangkap konten dari proses gagal, kita bisa menggunakan method catch() dari Axios.

axios.post(url, this.state)
.then(response => {
  // success
})
.catch(error => {
  // error
});

Lihat lagi pada contoh lengkap komponen VueJS di atas, saya memasukkan respons dari validasi ke dalam variabel errors.

Ketika variabel errors ini memiliki nilai berupa array, maka otomatis akan menampilkan pesan kesalahan pada masing-masing atribut pada formulir. Untuk pemanggilannya, kita bisa menggunakan potongan skrip di bawah pada view.

errros.email[0] // get first element

Sayangnya, potongan skrip di atas akan menghasilkan error di JavaScript client apabila variabel errors belum memiliki nilai atau index ke 0 dari key email tidak terdefinisi.

Oleh karena itu, saya memanfaatkan fungsi yang ada pada Lodash — method head ()— untuk mendapatkan value berdasarkan key paling pertama. Jika variabel errors ternyata kosong? Lodash akan mengembalikan nilai null sebagai default.

_.head(errors.email)

Pembaruan!

Hai, kesalahan saya, berhubung fungsi Lodash tidak bisa digunakan dalam template — tapi berjalan baik di Vue instance — , maka saya membuat method baru untuk mengambil data pada setiap key yang ada pada variabel errors.

Baca selengkapnya contoh kasus ini pada tautan berikut.

error(field) {
 return _.head(field);
}

Untuk menampilkan pesan kesalahannya pada setiap formulir, kita cukup memanggil fungsi tersebut pada template dengan argumen variabel errors dan key yang diinginkan. Misal:

error(errors.name);
error(errors.email);
error(errors.message);

Lalu, Bagaimana dengan CSRF Token?

Jika diperhatikan, setiap kali berurusan dengan form, seringkali kita mendapati kesalahan aplikasi karena lupa menyertakan CSRF token pada data yang dikirim. Selain melalui form, ternyata CSRF token juga dapat didefinisikan pada HTTP header dengan nama X-CSRF-TOKEN.

Menariknya, dalam proses AJAX di atas, kita tidak perlu mendefinisikan token melalui form data maupun melalui header, dan aplikasi tetap berjalan sempurna. Kenapa? Karena Laravel sudah menambahkan header yang berisi CSRF token pada global config Axios. Skripnya dapat dilihat pada berkas resources/assets/js/bootstrap.js.

window.axios.defaults.headers.common = {
    'X-CSRF-TOKEN': window.Laravel.csrfToken,
    'X-Requested-With': 'XMLHttpRequest'
};

Lantas, dari mana variabel Laravel berasal? Variabel ini didefinisikan dan berada pada berkas resources/views/layouts/app.blade.php pada baris 17 sampai dengan 21.

<script>
    window.Laravel = {!! json_encode([
        'csrfToken' => csrf_token(),
    ]) !!};
</script>

Contoh Aplikasi

Contoh aplikasi dapat kalian clone atau lihat pada repositori berikut.

laravel-id/ajax-form

ajax-form – Ajax form using VueJS and Laravel

Selain itu, demo aplikasi juga dapat kalian lihat dengan mengklik tautan ini.


Biar tidak terlalu bingung, pastikan kalian paham betul dasar penggunaan Laravel dan VueJS, konsep AJAX, proses kembalian data, dan lain sebagainya.

Masih bingung juga? Jangan sungkan untuk bertanya melalui halaman publikasi ini. 😉

Tak Berkategori

Yugo Purwanto

Pemrogram PHP dan JavaScript yang sedang sibuk mengembangkan aplikasi Glosarium Bahasa Indonesia.

2 comments

  1. saya juga mempunyai kasus yang sama dengan menghandle error ini, khususnya url error yang ditampilkan di console, ada solusi gk ya. kurang clean kesannya

Tinggalkan Balasan