Diterbitkan: 8 Agustus 2019
Banyak pengembang membuat kontrol formulir khusus, baik untuk menyediakan kontrol yang tidak terpasang di browser, atau untuk menyesuaikan tampilan dan nuansa di luar apa yang dimungkinkan dengan kontrol formulir bawaan.
Namun, mungkin sulit untuk meniru fitur kontrol formulir HTML bawaan. Pertimbangkan beberapa fitur yang didapat elemen <input> secara otomatis saat Anda menambahkannya ke formulir:
- Input akan otomatis ditambahkan ke daftar kontrol formulir.
- Nilai masukan secara otomatis dikirimkan bersama formulir.
- Input berpartisipasi dalam validasi formulir. Anda dapat memberi gaya pada input menggunakan pseudo-kelas
:validdan:invalid. - Masukan akan diberitahukan saat formulir disetel ulang, saat formulir dimuat ulang, atau saat browser mencoba mengisi otomatis entri formulir.
Kontrol formulir kustom biasanya memiliki beberapa fitur ini. Pengembang dapat mengatasi beberapa keterbatasan dalam JavaScript, seperti menambahkan <input> tersembunyi ke formulir untuk berpartisipasi dalam pengiriman formulir. Namun, fitur lain tidak dapat direplikasi hanya dengan JavaScript.
Dua fitur web memudahkan pembuatan kontrol formulir kustom, dan menghapus batasan kontrol kustom:
- Peristiwa
formdatamemungkinkan objek JavaScript sembarang berpartisipasi dalam pengiriman formulir, sehingga Anda dapat menambahkan data formulir tanpa menggunakan<input>tersembunyi. - API elemen kustom yang terkait dengan formulir memungkinkan elemen kustom bertindak lebih seperti kontrol formulir bawaan.
Kedua fitur ini dapat digunakan untuk membuat jenis kontrol baru yang bekerja lebih baik.
API berbasis peristiwa
Peristiwa formdata adalah API tingkat rendah yang memungkinkan kode JavaScript apa pun berpartisipasi dalam pengiriman formulir.
- Tambahkan pemroses peristiwa
formdatake formulir yang ingin Anda ajak berinteraksi. - Saat pengguna mengklik kirim, formulir akan memicu peristiwa
formdata, yang mencakup objekFormDatayang menyimpan semua data yang dikirimkan. - Setiap pemroses
formdatamemiliki kesempatan untuk menambahkan atau mengubah data sebelum formulir dikirimkan.
Berikut contoh pengiriman nilai tunggal dalam pendengar peristiwa formdata:
const form = document.querySelector('form');
// FormData event is sent on <form> submission, before transmission.
// The event has a formData property
form.addEventListener('formdata', ({formData}) => {
// https://developer.mozilla.org/docs/Web/API/FormData
formData.append('my-input', myInputValue);
});
Elemen kustom terkait formulir
Anda dapat menggunakan API berbasis peristiwa dengan jenis komponen apa pun, tetapi API ini hanya memungkinkan Anda berinteraksi dengan proses pengiriman.
Kontrol formulir standar berpartisipasi dalam banyak bagian siklus proses formulir. Elemen khusus yang terkait dengan formulir bertujuan untuk menjembatani kesenjangan antara widget khusus dan kontrol bawaan. Elemen kustom terkait formulir cocok dengan banyak fitur elemen formulir standar:
- Saat Anda menempatkan elemen kustom terkait formulir di dalam
<form>, elemen tersebut akan otomatis dikaitkan dengan formulir, seperti kontrol yang disediakan browser. - Elemen dapat diberi label menggunakan elemen
<label>. - Elemen dapat menetapkan nilai yang dikirimkan secara otomatis bersama formulir.
- Elemen dapat menyetel tanda yang menunjukkan apakah elemen tersebut memiliki input yang valid atau tidak. Jika salah satu kontrol formulir memiliki input yang tidak valid, formulir tidak dapat dikirimkan.
- Elemen dapat memberikan callback untuk berbagai bagian siklus proses formulir, seperti saat formulir dinonaktifkan atau direset ke status defaultnya.
- Elemen ini mendukung pseudokelas CSS standar untuk kontrol formulir, seperti
:disableddan:invalid.
Dokumen ini tidak mencakup semuanya, tetapi menjelaskan dasar-dasar yang diperlukan untuk mengintegrasikan elemen kustom Anda dengan formulir.
Tentukan elemen kustom yang terkait dengan formulir
Untuk mengubah elemen kustom menjadi elemen kustom terkait formulir, diperlukan beberapa langkah tambahan:
- Tambahkan properti
formAssociatedstatis ke class elemen kustom Anda. Hal ini memberi tahu browser untuk memperlakukan elemen seperti kontrol formulir. - Panggil metode
attachInternals()pada elemen untuk mendapatkan akses ke metode dan properti tambahan untuk kontrol formulir, sepertisetFormValue()dansetValidity(). - Tambahkan properti dan metode umum yang didukung oleh kontrol formulir, seperti
name,value, danvalidity.
Berikut cara item tersebut sesuai dengan definisi elemen kustom dasar:
// Form-associated custom elements must be autonomous custom elements.
// They must extend HTMLElement, not one of its subclasses.
class MyCounter extends HTMLElement {
// Identify the element as a form-associated custom element
static formAssociated = true;
constructor() {
super();
// Get access to the internal form control APIs
this.internals_ = this.attachInternals();
// internal value for this control
this.value_ = 0;
}
// Form controls usually expose a "value" property
get value() { return this.value_; }
set value(v) { this.value_ = v; }
// The following properties and methods aren't strictly required,
// but browser-level form controls provide them. Providing them helps
// ensure consistency with browser-provided controls.
get form() { return this.internals_.form; }
get name() { return this.getAttribute('name'); }
get type() { return this.localName; }
get validity() {return this.internals_.validity; }
get validationMessage() {return this.internals_.validationMessage; }
get willValidate() {return this.internals_.willValidate; }
checkValidity() { return this.internals_.checkValidity(); }
reportValidity() {return this.internals_.reportValidity(); }
…
}
customElements.define('my-counter', MyCounter);
Setelah terdaftar, Anda dapat menggunakan elemen ini di mana pun Anda menggunakan kontrol formulir yang disediakan browser:
<form>
<label>Number of bunnies: <my-counter></my-counter></label>
<button type="submit">Submit</button>
</form>
Tetapkan nilai
Metode attachInternals() mengembalikan objek ElementInternals yang menyediakan akses ke API kontrol formulir. Yang paling mendasar adalah metode setFormValue(), yang menetapkan nilai kontrol saat ini.
Metode setFormValue() dapat mengambil salah satu dari tiga jenis nilai:
- Nilai string.
- Objek
File. - Objek
FormData. Anda dapat menggunakan objekFormDatauntuk meneruskan beberapa nilai. Misalnya, kontrol masukan kartu kredit mungkin meneruskan nomor kartu, tanggal kedaluwarsa, dan kode verifikasi.
Untuk menetapkan nilai:
this.internals_.setFormValue(this.value_);
Untuk menetapkan beberapa nilai, Anda dapat melakukan sesuatu seperti ini:
// Use the control's name as the base name for submitted data
const n = this.getAttribute('name');
const entries = new FormData();
entries.append(n + '-first-name', this.firstName_);
entries.append(n + '-last-name', this.lastName_);
this.internals_.setFormValue(entries);
Validasi masukan
Kontrol Anda juga dapat berpartisipasi dalam validasi formulir dengan memanggil metode setValidity() pada objek internal.
// Assume this is called whenever the internal value is updated
onUpdateValue() {
if (!this.matches(':disabled') && this.hasAttribute('required') &&
this.value_ < 0) {
this.internals_.setValidity({customError: true}, 'Value cannot be negative.');
}
else {
this.internals_.setValidity({});
}
this.internals.setFormValue(this.value_);
}
Anda dapat memberi gaya pada elemen kustom terkait formulir dengan pseudokelas :valid dan :invalid, seperti kontrol formulir bawaan.
Callback siklus proses
API elemen kustom terkait formulir menyertakan serangkaian panggilan balik siklus hidup tambahan untuk dikaitkan dengan siklus hidup formulir. Panggilan balik bersifat opsional: hanya terapkan panggilan balik jika elemen Anda perlu melakukan sesuatu pada titik tersebut dalam siklus hidup.
void formAssociatedCallback(form)
Dipanggil saat browser mengaitkan elemen dengan elemen formulir, atau memisahkan elemen dari elemen formulir.
void formDisabledCallback(disabled)
Disebut setelahdisabled negara dari elemen berubah, baik karenadisabled atribut elemen ini ditambahkan atau dihapus; atau karenadisabled keadaan berubah pada<fieldset> Itu adalah nenek moyang unsur ini.
Elemen tersebut dapat, misalnya, menonaktifkan elemen dalam shadow DOM-nya saat dinonaktifkan.
void formResetCallback()
Dipanggil setelah formulir disetel ulang. Elemen harus mereset dirinya sendiri ke semacam
status default. Untuk elemen <input>, hal ini biasanya melibatkan penetapan properti value agar cocok dengan atribut value yang ditetapkan dalam markup. Dengan kotak centang, ini terkait dengan pengaturan properti checked agar sesuai dengan atribut checked.
void formStateRestoreCallback(state, mode)
Dipanggil dalam salah satu dari dua situasi:
- Saat browser memulihkan status elemen, seperti setelah navigasi atau saat browser dimulai ulang. Argumen
modeadalah"restore". - Saat fitur bantuan input browser seperti pengisian otomatis formulir menetapkan
nilai. Argumen
modeadalah"autocomplete".
Jenis argumen pertama bergantung pada cara metode setFormValue() dipanggil.
Memulihkan status formulir
Dalam beberapa situasi, seperti saat menavigasi kembali ke suatu halaman atau memulai ulang peramban, peramban mungkin mencoba mengembalikan formulir ke keadaan saat pengguna meninggalkannya.
Untuk elemen kustom terkait formulir, status yang dipulihkan berasal dari nilai yang Anda teruskan ke metode setFormValue(). Anda dapat memanggil metode dengan satu parameter nilai, seperti yang ditunjukkan dalam contoh sebelumnya, atau dengan dua parameter:
this.internals_.setFormValue(value, state);
value merepresentasikan nilai kontrol yang dapat dikirimkan. Parameter state opsional adalah representasi internal dari status kontrol, yang dapat menyertakan data yang tidak dikirim ke server. Parameter state mengambil tipe yang sama dengan parameter value: objek string, File, atau FormData.
Parameter state berguna jika Anda tidak dapat memulihkan status kontrol berdasarkan
nilai saja. Misalnya, Anda membuat pemilih warna dengan beberapa mode: palet atau roda warna RGB. Nilai yang dapat dikirimkan adalah warna yang dipilih dalam bentuk kanonik, seperti "#7fff00". Untuk mengembalikan kontrol ke status tertentu, Anda juga perlu mengetahui modenya, sehingga status mungkin terlihat seperti "palette/#7fff00".
this.internals_.setFormValue(this.value_,
this.mode_ + '/' + this.value_);
Kode Anda perlu memulihkan statusnya berdasarkan nilai status yang tersimpan.
formStateRestoreCallback(state, mode) {
if (mode == 'restore') {
// expects a state parameter in the form 'controlMode/value'
[controlMode, value] = state.split('/');
this.mode_ = controlMode;
this.value_ = value;
}
// Chrome doesn't handle autofill for form-associated custom elements.
// In the autofill case, you might need to handle a raw value.
}
Dalam kasus kontrol yang lebih sederhana (misalnya input angka), nilai
mungkin cukup untuk memulihkan kontrol ke status sebelumnya. Jika Anda menghilangkan state saat memanggil setFormValue(), maka nilainya akan diteruskan ke formStateRestoreCallback().
formStateRestoreCallback(state, mode) {
// Simple case, restore the saved value
this.value_ = state;
}
Deteksi fitur
Anda dapat menggunakan deteksi fitur untuk menentukan apakah peristiwa formdata dan elemen kustom terkait formulir tersedia. Tidak ada polyfill yang dirilis untuk kedua fitur tersebut. Dalam kedua kasus, Anda dapat kembali menambahkan elemen formulir tersembunyi untuk menyebarkan nilai kontrol ke formulir.
Banyak fitur yang lebih canggih dari elemen kustom terkait formulir kemungkinan sulit atau tidak mungkin untuk di-polyfill.
if ('FormDataEvent' in window) {
// formdata event is supported
}
if ('ElementInternals' in window &&
'setFormValue' in window.ElementInternals.prototype) {
// Form-associated custom elements are supported
}
Peristiwa formdata memberi Anda antarmuka untuk menambahkan data formulir ke proses pengiriman, tanpa harus membuat elemen <input> tersembunyi. Dengan API elemen kustom terkait formulir, Anda dapat menyediakan serangkaian kemampuan baru untuk kontrol formulir kustom yang berfungsi seperti kontrol formulir bawaan.