Memakai Autocomplete Widget Di Spring Web MVC


Saya memiliki sebuah halaman pencarian dimana pengguna bisa mengetik keyword pencarian, lalu isi halaman akan diperbaharui berdasarkan keyword tersebut secara AJAX.   Perubahan isi konten secara otomatis mungkin akan memberatkan browser pengguna; selain itu, saya harus men-query seluruh data setiap kali pengguna melakukan perubahan keyword yang di-ketik.  Bayangkan seorang pengguna yang menekan backspace, mengetik satu huruf, menekan backspace, mengetik dua huruf, menekan backspace dua kali, dan seterusnya.  Berapa kali harus request AJAX yang dilakukan ke server?  Hal ini dapat diatasi dengan AutoComplete widget dari jQuery UI yang memiliki option delay yang akan menunggu sesuai dengan milliseconds yang diberikan sebelum menghubungi server.   Dengan memakai Autocomplete widget, maka isi konten tidak lagi diperbaharui secara otomatis, tetapi seiring pengguna mengetik, akan muncul panduan keyword yang bisa dipilih oleh pengguna.

Berikut ini adalah kode HTML untuk bagian pencarian:

<div class="search custom_general_menu">
  <form name="formSearch" id="formSearch" action="#" method="post">
    <p>
      <input name="keyword" id="keyword" placeholder="Cari menu makanan..." type="text" />
      <input value="" id="cariMenu" class="btnsearch" type="submit" />
    </p>
  </form>
</div>

Untuk memakai Autocomplete widget, maka saya menambahkan baris berikut ini di halaman jspx tersebut:

...
  <spring:url value="/menumakanan/autocomplete" var="urlAutocomplete" />
  ...
  <script type="text/javascript">
     ...
     $("input#keyword").autocomplete({
        delay: 500,
        minLength: 3,
        source: "${urlAutocomplete}"
     });
     ...
  </script>
...

Pada konfigurasi di atas, setelah 500 ms  sejak user mengetik sebuah huruf  baru akan dilakukan request ke URL /menumakanan/autocomplete, dimana akan dilewatkan parameter term berupa keyword yang diketik oleh user.

Okay, bagian sisi web front-end sudah selesai, sekarang saya perlu melakukan perubahan di sisi back-end.

Saya akan mulai dengan menambahkan sebuah query baru yang hanya mengembalikan String di MenuMakananRepository.java.  Karena saya memakai Spring Data JPA, saya hanya perlu menambah sebuah method baru dengan isi seperti berikut ini:

...
@Query("SELECT menu.namaMenu FROM MenuMakanan menu WHERE menu.namaMenu LIKE :namaMenu")
List<String> findNamaMenuMakanan(@Param("namaMenu") String namaMenuMakanan);
...

Setelah itu, saya menambahkan sebuah service baru di MenuMakananService.java dengan isi seperti berikut ini:

...
public List<String> getNamaMenuMakanan(String namaMenuYangDicari) {
  return menuMakananRepository.findNamaMenuMakanan(
    String.format("%%%s%%", namaMenuYangDicari));
}
...

Sampai disini, saya akan membuat test case pada unit test MenuMakananService tersebut untuk memastikan bahwa tidak ada yang salah pada kode program.  Mm, kadang-kadang saya suka memakai test driven development (TDD) dimana saya membuat unit test terlebih dahulu baru membuat kode program di atas.  Biasanya, saya mengikuti  prinsip TDD hanya jika saya masih belum memahami sepenuhnya apa yang harus saya buat.

Setelah memastikan tidak ada yang salah di service layer, saya akan lanjut ke controller.   Saya akan membuat sebuah class Java yang mewakili JSON yang akan dikembalikan nanti.  Isi class tersebut akan terlihat seperti:

public class Autocomplete {

  public String value;

  public Autocomplete(String value) {
     this.value = value;
  }

  public String getValue() {
     return value;
  }

  public void setValue(String value) {
     this.value = value;
  }
}

Class ini nantinya akan diterjemahkan menjadi JSON oleh Jackson.  Format JSON ini yang diharapkan oleh Autocomplete widget adalah seperti berikut ini:

[
  {label: 'Item 1', value: 'KODE1'},
  {label: 'Item 2', value: 'KODE2'},
  {label: 'Item 3', value: 'KODE3'}
]

Nilai label akan ditampilkan dalam popup nanti, sementara nilai value akan dimasukkan ke dalam text box. Karena umumnya, kedua nilai tersebut sama, maka Autocomplete widget juga menerima JSON seperti berikut ini:

[
  {value: 'Item 1'},
  {value: 'Item 2'},
  {value: 'Item 3'}
]

Dengan demikian, untuk menghasilkan format JSON di atas, saya hanya perlu meletakkan setiap object Autocomplete ke dalam sebuah List.

Sekarang, saya tinggal menambahkan sebuah method baru di controller MenuMakananController.java dengan isi seperti berikut ini:

...
@RequestMapping(value="autocomplete")
@ResponseBody
public List<Autocomplete> autocomplete(@RequestParam("term") String term) {
   return (List<Autocomplete>) CollectionUtils.collect(menuMakananService.getNamaMenuMakanan(term),
     new Transformer() {
       @Override
       public Object transform(Object input) {
          return new Autocomplete((String) input);
       }
     }
   });
}
...

Pada kode program controller di atas, saya memakai class CollectionUtils dari Apache Commons Collections untuk menyederhanakan kode program.  Sesungguhnya, perbedaan jumlah baris tidak terlalu beda jauh dibanding membuat kode looping for biasa, tetapi saya selalu membiasakan diri untuk tidak melakukan reinvent the wheel (kecuali untuk kasus-kasus tertentu, misalnya tweaking kinerja kode program).  Well,  seorang computer scientist akan tertarik mempelajari kode program internal dan seluk-beluknya (bahkan membuat sesuatu yang baru yang lebih baik!), tetapi seorang software developer harus berusaha menyelesaikan sebuah tugas secara efisien dan secepat mungkin.

Sekarang, bila saya menjalankan halaman web tersebut,  Autocompletion widget akan bekerja seperti yang terlihat di gambar berikut ini:

Tampilan Autocomplete widget

Tampilan Autocomplete widget

Perihal Solid Snake
I'm nothing...

One Response to Memakai Autocomplete Widget Di Spring Web MVC

  1. Agung Setiawan mengatakan:

    mantap bang tutorialnya, heran kalau artikel-artikel programming yang advanced gini jarang banget yang komen, kalau basic-basic dan amburadul macam Jdbc yang tanpa layering banyak yang komen haha

    sekalian ninggalin link ya bang
    http://agung-setiawan.com

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: