> ## 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.

# サブフォーム

> DingTalk YiDAのサブフォームコンポーネントの概念、活用シーン、基本機能、高度な機能を解説します。設定パネルの刷新、操作ボタンの並び順の最適化、一括インポート・エクスポート機能に加え、よくある質問への回答も紹介します。

## 1. サブフォームとは

テキスト、数値、日付などのコンポーネントを内部に追加できる高機能なコンテナコンポーネントです。たとえば、商品データを入力する際に複数の商品エントリを追加する場合などに使用します。

## 2. 活用シーン

サブフォームは、出庫伝票、入庫伝票、販売伝票などのデータ入力によく使用されます。これらのシーンでは、商品明細をサブフォームに記録し、実際に入力するデータに応じて必要な行数を追加できます。

<Note>
  コンポーネントの属性、使い方、例については、[**コンポーネントインターフェースの説明**](/ja/open/yida/components/interface) をご参照ください。
</Note>

## 3. 基本機能

| **アップグレード項目**                                          | **変更前**                                | **変更後**                                                                                                                                                    |
| ------------------------------------------------------ | -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 設定パネル                                                  | 設定項目が分類されずに混在しており、探しにくい状態でした。          | サブフォームの設定ロジックに沿ってグループ化され、見つけやすくなりました。<br />ユーザーからのフィードバックに基づき、設定オプションを追加しました。                                                                              |
| サブフォーム操作ボタンの並び順（編集モード）                                 | 新規追加した操作が先頭に表示され、コピーボタンがありません。         | 有効にすると、「コピー」と「削除」ボタンがメインボタンとして先頭に配置され、続いてユーザー定義の操作ボタン、最後に「上下移動」ボタン（有効時に表示）が並びます。<br />編集モードでは、すべてのボタンがデフォルトで表示されます。<br />**注意：コピーボタンはまだ全面的にはリリースされていません。** |
| サブフォーム操作ボタンの並び順（記入モード）                                 | コピー操作に非対応で、並び替えボタンがデフォルトで表示されます。       | 初期状態（レコードが1件のみ）：削除は利用できません。                                                                                                                                |
| タイル表示モードに折り畳み／展開機能を追加                                  | すべてのレコードが表示されます。20件を超える場合はページング表示されます。 | （タイル表示モードでは、下図の赤枠のアイコンをクリックして展開／折り畳みを切り替えます。）                                                                                                              |
| 列を固定（スプレッドシートモード）<br />**現時点では、PCでの先頭列の固定のみに対応しています。** | 列の固定に非対応。                              | カスタム列の固定に対応（最大5列まで）。<br />**行番号は1列としてカウントされます。**<br />デフォルト：なし                                                                                             |
| 行番号名のカスタマイズ（タイル表示モード）                                  | 行番号名を設定できません。                          | 行番号名をカスタマイズできます。                                                                                                                                           |

### 3.1 レイアウトモード

サブフォームのレイアウトを設定します。デフォルトではスプレッドシートモードが使用されます。

#### 3.1.1 スプレッドシートモード

スプレッドシート

表示イメージ：

**注意**：件名およびヘッダーの表示は、レイアウトモードがスプレッドシートの場合、PCでのみ利用できます。

#### 3.1.2 タイル表示モード

タイル表示

表示イメージ：

### 3.2 追加ボタン名の設定

追加ボタンの名前は、デフォルトで「Add one」となっています。名前はカスタマイズできます。例：

追加ボタン名の設定

### 3.3 削除ボタン名の設定

削除ボタン名の設定

### 3.4 追加可能な最大レコード数

| **機能**              | **Freeプラン** | **ベーシック版** | **プロフェッショナル版** | **専用版** |
| ------------------- | ----------- | ---------- | -------------- | ------- |
| サブフォームに追加可能な最大レコード数 | 50          | 500        | 500            | 500     |

サブフォームの最大レコード数

### 3.5 サブフォームの列幅

列幅はカスタマイズ可能なため、長いコンテンツも正しく表示されます。

サブフォームの列幅のカスタマイズ

### 3.6 一括インポート

操作手順：フォームを開くと、サブフォームの下に「一括インポート」ボタンが表示されます。ボタンをクリックして操作を進めてください。（フォームで公開アクセス（サイレントログイン）が有効になっている場合、フォーム内のサブフォームは一括インポートに対応しません。）

**サブフォームの一括インポートテンプレートのフィールド順序は、フォーム設計時のフィールド順序と一致します。**

アクセスページ

* サブフォームデータの効率的な入力：Excelによる一括インポートに対応します。

一括インポートページ

インポート成功後：

### 3.7 一括エクスポート

* サブフォームデータの高速エクスポート：

一括エクスポート

一括エクスポート実行中

一括エクスポート成功

### 3.8 メインフォーム＋サブフォームのコンテンツを一括でExcelにエクスポート

* メインフォームデータとサブフォームデータを一括でエクスポートできます。

* 新しいエクスポート機能：

フォームページ

データ詳細情報ページ

Excelスプレッドシートページ

## 4. 高度な機能

### 4.1 操作列

#### 4.1.1 操作列の作成

操作列を作成したら、「編集」をクリックしてアクションをバインドします。

操作列

表示イメージ：

#### 4.1.2 コールバック関数

[**アクション設定**](/ja/yida/form/snftao) をご参照ください。

アクション - Item-0

コールバック関数

JSパネル

#### 4.1.3 カスタムレンダリング

JSXに対応しています。

カスタムレンダリング - アクションのバインド

表示イメージ：

## 5. FAQ

<AccordionGroup>
  <Accordion id="q1" title="5.1 サブフォームのレコードを一括削除するには？">
    <Check>
      サブフォームコンポーネントには、少なくとも1件のレコードを残す必要があります。
    </Check>

    以下のように、削除アクションを設定してください：

    **注意**：このアクションはデフォルトですべてのレコードを削除します。選択による一括削除には現時点で対応していません。
  </Accordion>

  <Accordion id="q2" title="5.2 サブフォーム内の特定のコンポーネントの値を取得するには？">
    サブフォームのデータを取得し、フォームバリデーションやデータソース呼び出しの入力パラメータとして使用したい場合に用います。

    **サンプルコード：**

    ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const subFormInst = this.$('subform unique identifier');
    // まず、行識別子を取得します
    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 サブフォームに関連するサブフォーム＆サブフォームへの値の代入">
    アプリを跨いだサブフォームデータの関連付けや、フォーム読み込み時のサブフォームデータの初期化によく使用されます。

    **参考：** [**明細同士の関連**](/ja/open/yida/components/form/tableField)
  </Accordion>

  <Accordion id="q4" title="5.4 サブフォームデータのエクスポート＆サブフォームデータのレポート分析">
    サブフォームのデータはデータ管理ページでの表示、分析、エクスポートができないため、レポートページ上のスプレッドシートでサブフォームデータを表示・エクスポートする必要があります。

    **参考：** **サブフォームデータのレポート分析**
  </Accordion>

  <Accordion id="q5" title="5.5 サブフォームでリダイレクト関数を設定した場合、その関数を実行するボタンを一度クリックした後に非表示にできますか？">
    カスタムレンダリングに以下のコードを追加することで実現できます：

    ```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'
     }}>アクションボタン名</div>;
    }
    ```
  </Accordion>

  <Accordion id="q6" title="5.6 サブフォームの上下移動ボタンを設定するには？">
    これは隠し機能です。フォームの編集ページに移動し、サブフォームの「並び替えを表示」を有効にすると、以下のように上下移動ボタンが表示されます：
  </Accordion>

  <Accordion id="q7" title="5.7 サブフォーム内の複数行テキストコンポーネントの1行分のテキストの一意性を検証できますか？">
    サブフォーム内のコンポーネントにカスタム検証関数を設定し、サブフォーム内のすべてのレコードを繰り返し処理して、現在のレコードと比較します。
  </Accordion>

  <Accordion id="q8" title="5.8 サブフォームのレコード総数を自動的に取得するには？">
    （1）サブフォームコンポーネントと数値コンポーネントを1つずつ配置し、数値コンポーネントのデフォルトを1に設定します。以下の通りです：

    （2）「サブフォーム」＞「プレミアム」＞「アクションを作成」の順にクリックします。onAddClickとonDelClickの2つのアクションを作成する必要があります。アクション作成時にコードを記述します。以下の通りです：

    以下のコードをそのまま使用できます。**注意**：1つ目の括弧内に数値コンポーネントの一意識別子、2つ目の括弧内にサブフォームの一意識別子を入力してください。設定については手順（3）をご参照ください。

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

    （3）まず、onAddClickアクションを作成します。以下の通りです：

    次に、上記のコードを貼り付けます：

    （4）onDelClickアクションを作成し、同じコードを貼り付けます：

    次に、上記のコードを貼り付けます：

    「保存」をクリックすると、結果は次のようになります：

    新しく追加したレコードを削除すると、カウントも自動的に減少します：
  </Accordion>

  <Accordion id="q9" title="5.9 変数でサブフォームのレコード数を制御するには？">
    （1）数値コンポーネントをドラッグして追加し、数値コンポーネントに「onChange」アクションをバインドします。

    （2）以下のコードを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" : "",   // サブフォーム内の別コンポーネントの一意識別子
        }
        a.push(b)
      }
      this.$("tableField_kurr4i2m").setValue(a)   // サブフォームコンポーネントの一意識別子
    }
    ```

    （3）結果：
  </Accordion>
</AccordionGroup>

### 5.10 サブフォーム内の非表示コンポーネントがnullを返す

サブフォームを処理する際、非表示属性を持つコンポーネントの`value`はリセットされ、nullに設定されます。そのため、非表示状態のサブフォームを別のサブフォームに代入するとnullが返されます。

<AccordionGroup>
  <Accordion id="q10" title="5.11 メインフォームのフィールド値に基づいてサブフォームコンポーネントの表示／非表示を制御するには？">
    メインフォームのフィールド値に基づいてサブフォームコンポーネントの状態を制御するには、以下の手順に従います：

    **変数 dp2 を作成**

    **サブフォーム内の一行テキストフィールドの状態を変数 state.dp2 にバインド**

    **メインフォームのセレクトドロップダウンにアクションをバインドし、状態を変数 dp2 に代入**

    サンプルコード：

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

  <Accordion id="q11" title="5.12 メインフォームの複数選択メンバーコンポーネントの値をサブフォームの複数レコードに反映するには？">
    以下のように、メインフォームのメンバーコンポーネントにアクションをバインドして代入を実行します：

    **サンプルコード：**

    ```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 }
          }
        })
        // 現在のページの明細コンポーネントに値を代入します
        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 1つのサブフォームには何個のコンポーネントフィールドを配置できますか？">
    サブフォームコンポーネントの中にサブフォームコンポーネントを挿入することはできませんが、その他の通常のコンポーネントは追加できます。Freeプランは最大20個、その他のエディションは最大100個まで対応しています。この上限を超えると、読み込みパフォーマンスが低下します。ビジネスロジックの分割を推奨します。
  </Accordion>
</AccordionGroup>

### 5.11 サブフォームデータの取得方法

共通のコンポーネントAPI `getValue` を使用してサブフォームデータを取得できます。

**サンプルコード：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
this.$('subform component unique identifier').getValue(); // サブフォームデータを取得
```

**レスポンス例：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
[
  {
    textField_lzjl01sh: '一行テキスト 1',
    numberField_lzjl01si: 1,
  }, {
    textField_lzjl01sh: '一行テキスト 2',
    numberField_lzjl01si: 2,
  }, {
    textField_lzjl01sh: '一行テキスト 3',
    numberField_lzjl01si: 3,
  }
]
```

### 5.12 サブフォームの行識別子を取得する方法

サブフォームAPI `getItems` を使用してサブフォームの行識別子を取得できます。

**サンプルコード：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
this.$('subform component unique identifier').getItems(); // サブフォームの行識別子を取得
```

**レスポンス例：**

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

### 5.13 サブフォームの特定行のデータを取得する方法

サブフォームAPI `getItemValue` を使用してサブフォームの特定行のデータを取得できます。

**サンプルコード：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
this.$('subform component unique identifier').getItemValue('row identifier of the specified row'); // 指定行のデータを取得
```

**レスポンス例：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  textField_lzjl01sh: '一行テキスト 2',
  numberField_lzjl01si: 2,
}
```

### 5.14 サブフォームのonChange発火時に現在変更されたフィールドを取得する方法

サブフォームのデータが変更されると、セルの変更だけでなく、数式の計算、データ連動、外部からの代入などによってもサブフォームのonChangeイベントがトリガーされます。変更内容を識別しやすくするため、サブフォームのonChangeイベントの`extra`パラメータで現在変更されたフィールドを、`changes`パラメータで変更されたフィールドの値を取得できます。

**サンプルコード：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// サブフォームのonChange
export function onTableChange({ value, extra }) {
  const { fieldId, changes = {} } = extra || {};
  // 商品名フィールドが変更されたかどうかを確認します
  if (fieldId && fieldId === 'unique identifier of the item name field in the subform') {
    // フィールド変更後に実行するロジックをここに追加します
    console.log(changes.value);
  }
}
```

**結果：**

### 5.15 サブフォーム内のコンポーネントが変更されたときに、現在の行の他のフィールドを更新する方法

サブフォームAPI `updateItemValue` を使用して、サブフォームの現在の行の他のフィールドを更新できます。

<Note>
  注意：このAPIはサブフォームコンポーネントのイベントでのみ使用でき、サブフォーム内のコンポーネントのイベントでは使用できません。
</Note>

**サンプルコード：**

```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}}
// サブフォームのonChange
export function onTableChange({ value, extra }) {
  const { formGroupId, from, tableFieldId, fieldId, changes = {} } = extra || {};
  // updateItemValueでサブフォームデータを更新すると再度onChangeがトリガーされ、無限ループが発生するのを防ぐために必要です
  if (from === 'setItemValue') { return; }
  const tableField = this.$(tableFieldId); // サブフォームの定義を取得
  // 商品名フィールドが変更されたかどうかを確認します
  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',
    }); // 現在の行の他のコンポーネントの値を更新
  }
}
```

**結果：**

商品名を入力すると、現在の行の**商品名**の値が**商品名のコピー**に代入されます。
