> ## Documentation Index
> Fetch the complete documentation index at: https://help.dingtalk.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Subformulir

> Pelajari cara menggunakan subformulir di YiDA untuk entri data massal — dari mode tata letak, impor/ekspor Excel, kolom tindakan, hingga rendering kustom bagi admin low-code.

## 1. Apa itu subformulir

Komponen kontainer tingkat lanjut yang memungkinkan Anda menambahkan komponen Teks, Numerik, Tanggal, dan lainnya di dalamnya. Contohnya, gunakan komponen ini ketika Anda perlu menambahkan beberapa entri produk selama proses entri data produk.

## 2. Kasus penggunaan

Subformulir umumnya digunakan untuk entri data, seperti pesanan keluar, pesanan masuk, dan pesanan penjualan. Rincian produk dalam skenario ini dapat dicatat dalam subformulir, dan Anda dapat menambahkan baris sesuai kebutuhan berdasarkan data aktual yang akan dimasukkan.

<Note>
  Untuk atribut komponen, penggunaan, dan contoh, [**klik di sini**](/id/open/yida/components/interface).
</Note>

## 3. Fitur dasar

| **Item peningkatan**                                                                                      | **Sebelumnya**                                                                     | **Sesudah**                                                                                                                                                                                                                                                                                                                                                |
| --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Panel pengaturan                                                                                          | Pengaturan tercampur tanpa pengelompokan sehingga sulit ditemukan.                 | Pengaturan dikelompokkan berdasarkan logika konfigurasi subformulir agar mudah ditemukan.<br />Berdasarkan masukan pengguna yang sering, opsi konfigurasi tambahan telah ditambahkan.                                                                                                                                                                      |
| Urutan tombol tindakan subformulir (mode edit)                                                            | Tindakan yang baru ditambahkan ditampilkan lebih dulu, dan tidak ada tombol Salin. | Setelah diaktifkan, tombol "Salin" dan "Hapus" menjadi tombol utama yang ditempatkan di depan, diikuti oleh tombol tindakan yang ditentukan pengguna, dan terakhir tombol "Pindah ke atas/bawah" (ditampilkan saat diaktifkan).<br />Pada mode edit, semua tombol ditampilkan secara default.<br />**Catatan: Tombol Salin belum sepenuhnya diluncurkan.** |
| Urutan tombol tindakan subformulir (mode kirim)                                                           | Tindakan salin tidak didukung, dan tombol pengurutan ditampilkan secara default.   | Kondisi awal (hanya satu rekaman): Hapus tidak tersedia.                                                                                                                                                                                                                                                                                                   |
| Ciutkan/perluas ditambahkan pada mode ubin                                                                | Semua rekaman ditampilkan. Jika terdapat lebih dari 20 rekaman, akan dipaginasi.   | (Pada mode ubin, klik ikon yang dilingkari merah di bawah ini untuk mengalihkan perluas/ciutkan.)                                                                                                                                                                                                                                                          |
| Bekukan kolom (mode spreadsheet)<br />**Saat ini, hanya pembekuan kolom terdepan pada PC yang didukung.** | Pembekuan kolom tidak didukung.                                                    | Pembekuan kolom kustom didukung, hingga 5 kolom.<br />**Nomor baris terhitung sebagai 1 kolom.**<br />Default: tidak ada                                                                                                                                                                                                                                   |
| Nama nomor baris kustom (mode ubin)                                                                       | Tidak ada pengaturan untuk nama nomor baris.                                       | Nama nomor baris dapat dikustomisasi.                                                                                                                                                                                                                                                                                                                      |

### 3.1 Mode tata letak

Tetapkan tata letak subformulir. Mode spreadsheet digunakan secara default.

#### 3.1.1 Mode spreadsheet

Spreadsheet

Tampilan efek:

**Catatan**: Tampilan subjek dan header hanya tersedia di PC ketika mode tata letak adalah Spreadsheet.

#### 3.1.2 Mode ubin

Ubin

Efek:

### 3.2 Tetapkan nama tombol Tambah

Nama tombol Tambah secara default adalah "Tambah satu". Anda dapat mengkustomisasi namanya. Contoh:

Tetapkan nama tombol Tambah

### 3.3 Tetapkan nama tombol Hapus

Tetapkan nama tombol Hapus

### 3.4 Jumlah maksimum rekaman yang dapat ditambahkan

| **Fitur**                                                     | **Paket Luang** | **Edisi Basic** | **Edisi Professional** | **Edisi Dedicated** |
| ------------------------------------------------------------- | --------------- | --------------- | ---------------------- | ------------------- |
| Jumlah maksimum rekaman yang dapat ditambahkan ke subformulir | 50              | 500             | 500                    | 500                 |

Jumlah maksimum rekaman subformulir

### 3.5 Lebar kolom subformulir

Lebar kolom dapat dikustomisasi, sehingga konten yang panjang pun ditampilkan dengan baik.

Kustomisasi lebar kolom subformulir

### 3.6 Impor massal

Jalur: Ketika Anda membuka formulir, Anda akan melihat tombol Impor massal di bawah subformulir. Klik Impor massal untuk melanjutkan. (Jika formulir memiliki akses publik (Login senyap) yang diaktifkan, subformulir di dalam formulir tidak mendukung impor massal.)

**Urutan bidang dalam templat impor massal subformulir sesuai dengan urutan bidang dalam desain formulir.**

Halaman akses

* Entri data subformulir yang efisien: Mendukung impor massal melalui Excel.

Halaman impor massal

Setelah impor berhasil:

### 3.7 Ekspor massal

* Ekspor cepat data subformulir:

Ekspor massal

Ekspor massal sedang berlangsung

Ekspor massal berhasil

### 3.8 Mendukung ekspor konten formulir utama + subformulir bersama-sama ke Excel

* Mendukung ekspor data formulir utama dan data subformulir secara bersamaan.

* Kemampuan ekspor baru:

Halaman formulir

Halaman rekaman sumber

Halaman spreadsheet Excel

## 4. Fitur lanjutan

### 4.1 Kolom tindakan

#### 4.1.1 Buat kolom tindakan

Setelah Anda membuat kolom tindakan, klik Edit untuk mengikat tindakan.

Kolom tindakan

Efek:

#### 4.1.2 Fungsi callback

Lihat [**Pengaturan tindakan**](/id/yida/form/snftao).

Tindakan - Item-0

Fungsi callback

Panel JS

#### 4.1.3 Rendering kustom

JSX didukung.

Rendering kustom - ikat tindakan

Efek:

## 5. FAQ

<AccordionGroup>
  <Accordion id="q1" title="5.1 Bagaimana cara menghapus rekaman secara massal dalam subformulir?">
    <Check>
      Komponen subformulir harus menyimpan minimal satu rekaman.
    </Check>

    Anda perlu mengkonfigurasi tindakan Hapus, seperti ditunjukkan di bawah ini:

    **Catatan**: Secara default, tindakan ini menghapus semua rekaman. Penghapusan massal berdasarkan pilihan belum didukung.
  </Accordion>

  <Accordion id="q2" title="5.2 Bagaimana cara mendapatkan nilai komponen tertentu di dalam subformulir?">
    Ini digunakan ketika Anda ingin mendapatkan data subformulir untuk validasi formulir atau sebagai parameter input untuk pemanggilan sumber data.

    **Kode contoh:**

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const subFormInst = this.$('subform unique identifier');
    // Pertama, dapatkan identifier baris
    const items = subFormInst.getItems(); //  ["tfitem_1", "tfitem_2"]
    items.forEach(item => {
      const fieldInst = subFormInst.getComponent(item, 'unique identifier of the component inside the subform');
      console.log(fieldInst.getValue());
    });
    ```
  </Accordion>

  <Accordion id="q3" title="5.3 Subformulir yang terkait dengan subformulir & penetapan nilai subformulir">
    Umumnya digunakan untuk asosiasi data subformulir lintas aplikasi dan inisialisasi data subformulir saat formulir dimuat.

    **Referensi:** [**Asosiasi rincian-ke-rincian**](/id/open/yida/components/form/tableField)
  </Accordion>

  <Accordion id="q4" title="5.4 Ekspor data subformulir & analisis laporan pada data subformulir">
    Karena data subformulir tidak dapat ditampilkan atau dianalisis pada halaman manajemen data dan tidak dapat diekspor, Anda perlu menampilkan dan mengekspor data subformulir dalam spreadsheet pada halaman laporan.

    **Referensi:** **Analisis laporan pada data subformulir**
  </Accordion>

  <Accordion id="q5" title="5.5 Jika saya menyiapkan fungsi pengalihan pada subformulir, dapatkah tombol yang menjalankan fungsi tersebut disembunyikan setelah diklik sekali?">
    Anda dapat mencapainya dengan menambahkan kode berikut di Rendering kustom:

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    export function onActionRender({ index, groupId, itemValue, actionKey }) {
     return <div id="anniu" onClick={()=>{
     document.getElementById('anniu').style.display = 'none'
     }}>Nama tombol tindakan</div>;
    }
    ```
  </Accordion>

  <Accordion id="q6" title="5.6 Bagaimana cara menyiapkan tombol pindah ke atas/bawah untuk subformulir?">
    Ini adalah fitur tersembunyi. Buka halaman edit formulir dan aktifkan "Tampilkan pengurutan" untuk subformulir. Tombol pindah ke atas/bawah kemudian akan muncul, seperti ditunjukkan di bawah ini:
  </Accordion>

  <Accordion id="q7" title="5.7 Dapatkah saya memvalidasi keunikan satu baris teks dalam komponen Teks multi-baris di dalam subformulir?">
    Konfigurasikan fungsi validasi kustom pada komponen di dalam subformulir, iterasikan semua rekaman dalam subformulir, dan bandingkan dengan rekaman saat ini.
  </Accordion>

  <Accordion id="q8" title="5.8 Bagaimana cara mendapatkan jumlah total rekaman dalam subformulir secara otomatis?">
    (1) Gunakan satu komponen subformulir dan satu komponen Numerik, lalu tetapkan nilai Default komponen Numerik menjadi 1, seperti ditunjukkan:

    (2) Klik Subformulir > Premium > Buat tindakan. Anda perlu membuat dua tindakan: satu untuk onAddClick dan satu untuk onDelClick. Tulis kode saat membuat tindakan, seperti ditunjukkan:

    Kode berikut dapat digunakan secara langsung. **Catatan**: Masukkan identifier unik komponen Numerik pada tanda kurung pertama, dan identifier unik subformulir pada tanda kurung kedua. Lihat langkah (3) untuk pengaturannya.

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    this.$('Numerical component identifier').setValue(this.$('Subform identifier').getValue().length);
    ```

    (3) Pertama, buat tindakan onAddClick, seperti ditunjukkan:

    Kemudian tempel kode di atas:

    (4) Buat tindakan onDelClick dan tempel kode yang sama:

    Kemudian tempel kode di atas:

    Setelah mengklik Simpan, hasilnya adalah:

    Ketika Anda menghapus rekaman yang baru ditambahkan, jumlahnya akan berkurang secara otomatis:
  </Accordion>

  <Accordion id="q9" title="5.9 Bagaimana cara mengontrol jumlah rekaman subformulir dengan variabel?">
    (1) Seret masuk komponen Numerik dan ikat tindakan "onChange" ke komponen Numerik.

    (2) Salin kode berikut ke dalam panel JS:

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    export function onChange({ value }) {
      console.log('onChange', value);
      let a = [];
      for(let i=0;i<value;i++){
        let b= {
          "textField_kurr4i2o" : "",   // Identifier unik komponen lain di dalam subformulir
        }
        a.push(b)
      }
      this.$("tableField_kurr4i2m").setValue(a)   // Identifier unik komponen subformulir
    }
    ```

    (3) Hasil:
  </Accordion>
</AccordionGroup>

### 5.10 Komponen tersembunyi dalam subformulir mengembalikan null

Ketika memproses subformulir, `value` dari atribut tersembunyi akan direset. Nilainya dikonfigurasi sebagai null, sehingga menetapkan subformulir dalam kondisi tersembunyi ke subformulir lain akan mengembalikan null.

<AccordionGroup>
  <Accordion id="q10" title="5.11 Bagaimana cara mengontrol status tampilkan/sembunyikan komponen subformulir berdasarkan nilai bidang formulir utama?">
    Untuk mengontrol status komponen subformulir berdasarkan nilai bidang formulir utama, ikuti langkah-langkah berikut:

    **Buat variabel dp2**

    **Ikat status bidang Teks satu baris di subformulir ke variabel state.dp2**

    **Ikat tindakan pada dropdown Pilih di formulir utama untuk menetapkan status ke variabel dp2**

    Kode contoh:

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    export function onChange({value, actionType, item}) {
      console.log('onChange', value);
      if(value=="Opsi 1"){
        this.setState({ dp2: "DISABLED"})
      }
      else{
        this.setState({ dp2: "HIDDEN" })
      }
    ```
  </Accordion>

  <Accordion id="q11" title="5.12 Bagaimana cara mengisi komponen anggota Pilih Banyak di formulir utama ke dalam beberapa rekaman di subformulir?">
    Ikat tindakan pada komponen anggota formulir utama untuk melakukan penetapan nilai, seperti ditunjukkan di bawah ini:

    **Kode contoh:**

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    export function onChange({ value }) {
      if (value && value.length > 0) {
        let newValue = value.map((item) => {
          return {
            "Unique identifier of the subform member component": { label: item.label, value: item.value }
          }
        })
        // Tetapkan nilai ke komponen rincian pada halaman saat ini
        this.$("Unique identifier of the subform component").setValue(newValue);
      } else {
        this.$("Unique identifier of the subform component").reset();
      }
    }
    ```
  </Accordion>

  <Accordion id="q12" title="5.13 Berapa banyak bidang komponen yang dapat ditempatkan dalam satu subformulir?">
    Anda tidak dapat menyisipkan komponen subformulir di dalam subformulir, tetapi Anda dapat menambahkan komponen reguler lainnya. Paket Luang mendukung hingga 20; edisi lainnya mendukung hingga 100. Melebihi batas ini akan menurunkan performa pemuatan. Kami merekomendasikan untuk memecah logika bisnis.
  </Accordion>
</AccordionGroup>

### 5.11 Bagaimana cara mendapatkan data subformulir

Anda dapat menggunakan API komponen umum `getValue` untuk mendapatkan data subformulir.

**Kode contoh:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
this.$('subform component unique identifier').getValue(); // Dapatkan data subformulir
```

**Contoh respons:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
[
  {
    textField_lzjl01sh: 'Teks satu baris 1',
    numberField_lzjl01si: 1,
  }, {
    textField_lzjl01sh: 'Teks satu baris 2',
    numberField_lzjl01si: 2,
  }, {
    textField_lzjl01sh: 'Teks satu baris 3',
    numberField_lzjl01si: 3,
  }
]
```

### 5.12 Bagaimana cara mendapatkan identifier baris subformulir

Anda dapat menggunakan API subformulir `getItems` untuk mendapatkan identifier baris subformulir.

**Kode contoh:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
this.$('subform component unique identifier').getItems(); // Dapatkan identifier baris subformulir
```

**Contoh respons:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
['tfitem_1', 'tfitem_2', 'tfitem_3']
```

### 5.13 Bagaimana cara mendapatkan data baris tertentu dalam subformulir

Anda dapat menggunakan API subformulir `getItemValue` untuk mendapatkan data baris tertentu dalam subformulir.

**Kode contoh:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
this.$('subform component unique identifier').getItemValue('row identifier of the specified row'); // Dapatkan data baris yang ditentukan
```

**Contoh respons:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  textField_lzjl01sh: 'Teks satu baris 2',
  numberField_lzjl01si: 2,
}
```

### 5.14 Bagaimana cara mendapatkan bidang yang saat ini berubah ketika onChange subformulir terpicu

Ketika data subformulir berubah, peristiwa onChange subformulir tidak hanya terpicu oleh perubahan sel, tetapi juga oleh perhitungan formula, keterkaitan data, atau penetapan nilai eksternal. Untuk membantu mengidentifikasi perubahan, Anda dapat menggunakan parameter `extra` dari peristiwa onChange subformulir untuk mendapatkan bidang yang saat ini berubah, dan parameter `changes` untuk mendapatkan nilai bidang yang berubah.

**Kode contoh:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Subformulir onChange
export function onTableChange({ value, extra }) {
  const { fieldId, changes = {} } = extra || {};
  // Periksa apakah bidang nama item telah berubah
  if (fieldId && fieldId === 'unique identifier of the item name field in the subform') {
    // Tambahkan logika yang akan dijalankan setelah bidang berubah di sini
    console.log(changes.value);
  }
}
```

**Hasil:**

### 5.15 Bagaimana cara memperbarui bidang lain di baris saat ini ketika komponen di dalam subformulir berubah

Anda dapat menggunakan API subformulir `updateItemValue` untuk memperbarui bidang lain di baris saat ini dari subformulir.

<Note>
  Catatan: API ini hanya dapat digunakan dalam peristiwa komponen subformulir, bukan dalam peristiwa komponen di dalam subformulir.
</Note>

**Kode contoh:**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Subformulir onChange
export function onTableChange({ value, extra }) {
  const { formGroupId, from, tableFieldId, fieldId, changes = {} } = extra || {};
  // Diperlukan untuk mencegah loop tak terbatas akibat pemicuan onChange kembali setelah menggunakan updateItemValue untuk memperbarui data subformulir
  if (from === 'setItemValue') { return; }
  const tableField = this.$(tableFieldId); // Dapatkan definisi subformulir
  // Periksa apakah bidang nama item telah berubah
  if (fieldId && fieldId === 'unique identifier of the item name field in the subform') {
    tableField.updateItemValue(formGroupId, {
      'unique identifier of another component in the current row': 'updated value',
    }); // Perbarui nilai komponen lain di baris saat ini
  }
}
```

**Hasil:**

Setelah memasukkan nama item, nilai **Nama item** akan ditetapkan ke **Salinan nama item** di baris saat ini.
