Sinau Coding
Berbincang santai perihal pemrograman
Tukang ketik yang sedang belajar pemrograman
6/13/2022 08:17:00 AM

Membuat promise based Modal/Dialog dengan menggunakan Vue 3 dan Quasar

Promise based Modal/Dialog dengan Vue 3

Artikel ini akan membahas salah satu cara mudah untuk membuat promise based komponen Modal/Dialog dengan menggunakan Vue 3 dan Quasar. Quasar dalam hal ini hanya sabagai contoh, dan algoritma ini dapat diterapkan pada UI framework yang lainnya.

Pada saat Anda menggunakan komponen Modal atau Dialog dari UI framework yang Anda gunakan, maka cara paling mudahnya adalah dengan menggunakan v-model. Dengan v-model tersebut Anda bisa menampilkan atau menyembunyikan Modal/Dialog cukup dengan mengganti nilai dari v-model-nya. Cara ini memang sangat mudah, akan tetapi Anda akan mengalami kesulitan jika Modal/Dialog tersebut ingin Anda jadikan komponen terpisah yang dapat dipanggil dari banyak halaman yang lain. Selain itu, Anda mungkin ingin menyederhanakan cara memanggil Modal/Dialog tersebut yaitu cukup dengan memanggil sebuah fungsi lalu menunggu hasil dari Modal tersebut.

Oleh karena itu, cara menggunakan Modal/Dialog di atas dapat disederhanakan dan dipermudah dengan menerapkan metode promise based Modal/Dialog, dimana dengan cara ini pengembang cukup memanggil sebuah fungsi (misalkan : open) untuk menampilkan Modal, lalu menunggu hasil balikan yang berupa promise.

Berikut ini adalah beberapa langkah untuk membuat promise based komponen Modal/Dialog dengan menggunakan Vue 3.


Baca juga :
Vue+Vuetify : Menggunakan VDialog/v-dialog agar menjadi Promise based komponen
1. Membuat komponen Modal/Dialog secara terpisah

Membagi aplikasi yang besar menjadi beberapa komponen yang lebih kecil adalah sebuah best practice untuk menyederhanakan struktur aplikasi sehingga lebih mudah untuk dibaca dan di-maintenance dikemudian hari. Oleh karena itu, silahkan pisahkan Modal atau Dialog Anda ke dalam komponen terpisah. Untuk contoh kali ini, kita akan membuat sebuah komponen Modal/Dialog dengan nama MyDialog. Komponen ini kita tempatkan ke dalam folder components dengan nama MyDialog.vue.

Struktur folder

Berikut ini adalah contoh kode awal dari komponen MyDialog.vue sebelum dimodifikasi menjadi promise based.

<template>
  <q-dialog v-model="dlg" persistent>
    <q-card dark>
      <q-toolbar>
        <span>Vue 3 Promise Dialog</span>
        <q-space></q-space>
        <q-btn size="sm" round icon="close"></q-btn>
      </q-toolbar>
      <q-card-section class="row items-center">
        <p>Silahkan pilih tombol dibawah ini</p>
      </q-card-section>

      <q-card-actions align="right">
        <q-btn label="Yes" color="primary" />
        <q-btn label="No" color="info" />
        <q-btn label="Ok" color="warning" />
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

<script setup>
import { ref } from 'vue';

const dlg = ref(false);
const open = () => {
    dlg.value = true;
  });
};

defineExpose({
  open,
});
</script>

Seperti biasa, Modal standar di atas terdiri atas toolbar yang berisi tombol close dan beberapa tombol action yang nantinya akan menghasilkan result yang berbeda. Untuk menampilkan atau menyembunyikan modal/dialog masih tetap dengan menggunakan v-model, dalam hal ini berupa variable dlg dengan tipe ref.

<template>
  <q-dialog v-model="dlg" persistent>
      ...
  </q-dialog>
</template>

<script setup>
import { ref } from 'vue';

const dlg = ref(false);
...

Jangan lupa, karena di sini menggunakan ref, maka untuk mengakses nilai dari ref dari dalam script harus dengan .value .

Fungsi open nantinya akan dipanggil dari halaman atau komponen lain. Isi dari fungsi open saat ini hanya men-set dlg menjadi true agar Modal muncul. Kemudian fungsi open ini kita expose agar dapat dipanggil dari luar, dengan menggunakan defineExpose.

...
const open = () => {
    dlg.value = true;
  });
};

defineExpose({
  open,
});
</script>
2. Menambahkan Promise

Komponen MyDialog di atas secara fungsi sudah bisa dipanggil dari luar, akan tetapi masih belum promise based. Untuk itu silahkan tambahkan variable untuk menyimpan parameter resolve dan reject dari Promise, kemudian modifikasi fungsi open agar mengembalikan promise. Pastikan Anda tidak lupa menuliskan return new Promise .

...

<script setup>
import { ref } from 'vue';

// variable untuk menyimpan funsi resolve dan reject dari Promise
var resolve = null;
var reject = null;

...

const open = () => {
    // membuat Promise baru
  return new Promise((res, rej) => {
    resolve = res;
    reject = rej;
    dlg.value = true;
  });
};

...
Variable resolve dan reject di sini tidak menggunakan ref dikarenakan dua varible ini TIDAK perlu reactive.

Kemudian silahkan buat 2 fungsi baru untuk me-resolve promise, misalkan dengan nama apply dan fungsi untuk re-reject promise, misalkan dengan nama cancel.

...
const apply = (text) => {
  dlg.value = false;
  resolve(text);
};

const cancel = () => {
  dlg.value = false;
  reject('rejected');
};

const open = () => {
  return new Promise((res, rej) => {
    resolve = res;
    reject = rej;
    dlg.value = true;
  });
};
...

Bind fungsi cancel pada tombol close, dan fungsi apply pada tombol yang lainnya atau yang Anda inginkan, seperti contoh berikut ini.

<template>
  <q-dialog v-model="dlg" persistent>
    <q-card dark>
      <q-toolbar>
        <span>Vue 3 Promise Dialog</span>
        <q-space></q-space>
        <q-btn size="sm" round icon="close" @click="cancel"></q-btn>
      </q-toolbar>
      <q-card-section class="row items-center">
        <p>Silahkan pilih tombol dibawah ini</p>
      </q-card-section>

      <q-card-actions align="right">
        <q-btn label="Yes" color="primary" @click="apply('yes')" />
        <q-btn label="No" color="info" @click="apply('no')" />
        <q-btn label="Ok" color="warning" @click="apply('ok')" />
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

Berikut ini adalah keseluruhan isi komponen MyDialog setelah diubah menjadi promise based.

<template>
  <q-dialog v-model="dlg" persistent>
    <q-card dark>
      <q-toolbar>
        <span>Vue 3 Promise Dialog</span>
        <q-space></q-space>
        <q-btn size="sm" round icon="close" @click="cancel"></q-btn>
      </q-toolbar>
      <q-card-section class="row items-center">
        <p>Silahkan pilih tombol dibawah ini</p>
      </q-card-section>

      <q-card-actions align="right">
        <q-btn label="Yes" color="primary" @click="apply('yes')" />
        <q-btn label="No" color="info" @click="apply('no')" />
        <q-btn label="Ok" color="warning" @click="apply('ok')" />
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

<script setup>
import { ref } from 'vue';

var resolve = null;
var reject = null;

const dlg = ref(false);
const apply = (text) => {
  dlg.value = false;
  resolve(text);
};
const cancel = () => {
  dlg.value = false;
  reject();
};
const open = () => {
  return new Promise((res, rej) => {
    resolve = res;
    reject = rej;
    dlg.value = true;
  });
};
defineExpose({
  open,
});
</script>
3. Menggunakan MyDialog dari halaman lain

Setelah komponen MyDialog di atas siap, berikut ini adalah cara menggunakan komponen tersebut dari halaman lain. Untuk contoh kali ini kita akan memanggil MyDialog dari halaman depan (App.vue) sebagai berikut.

<template>
  <q-layout>
    <q-page-container>
      <q-page padding>
        <p>Hasil Modal : {{ hasil }}</p>
        <q-btn @click="openDlg"> Show Modal </q-btn>
      </q-page>
      <MyDialog ref="dlg" />
    </q-page-container>
  </q-layout>
</template>

<script setup>
import MyDialog from './components/MyDialog.vue';
import { ref } from 'vue';
const hasil = ref('');

const dlg = ref('dlg');
const openDlg =  () => {
  dlg.value
    .open()
    .then((res) => {
      hasil.value = res;
    })
    .catch(() => {
      hasil.value = 'rejected';
    });  
};
</script>

Seperti biasa, langkah pertama adalah dengan meng-import komponen MyDialog. Kemudian tempatkan di dalam halaman, dengan tidak lupa menambahkan ref agar dapat diakses dalam dalam script.

<template>
  <q-layout>
      ...
      <MyDialog ref="dlg" />
      ...
  </q-layout>
</template>

<script setup>
import MyDialog from './components/MyDialog.vue';
import { ref } from 'vue';
const hasil = ref('');

const dlg = ref('dlg');

...
</script>

Kemudian silahkan buat fungsi (jika perlu), misalkan bernama openDlg untuk membuka Modal tersebut (yang telah di beri referensi dlg). Jangan lupa, untuk mengakses dlg harus dengan .value dan tambahkan .then .catch karena fungsi open mengembalikan Promise.

...
const openDlg = () => {
  dlg.value
    .open()
    .then((res) => {
      hasil.value = res;
    })
    .catch(() => {
      hasil.value = 'rejected';
    });
}

...

Hasil akhirnya kurang lebih seperti di bawah ini.

Fungsi open dari komponen MyDialog selain bisa dipanggil dengan syntax promise then catch, juga bisa dipanggil dengan menggunakan async await sebagai berikut.

...
const openDlg = async () => {

  try {
    hasil.value = await dlg.value.open()
  }
  catch {
    hasil.value = "rejected"
  }
  
};
...
Jika Anda menggunakan await, maka jangan lupa tambahkan async pada fungsi Anda.
Sekian tip dan trik kali ini. Selamat mencoba dan semoga yang sedikit ini bermanfaat.

Komentar

Load more