🎻

[Symfony] EntityTypeでoptionタグ1つ1つにエンティティの情報を持たせてフロントから利用する

2020/06/05に公開

例えばこんな要件

以下のようなフォームを作りたいとします。

  • 商品エンティティを選択できる
  • 選択した商品の値段をもとに、別の入力欄の初期値が自動で計算される

実装の方針

方針としては

  • EntityType でレンダリングされる <option> タグの1つ1つに、商品の値段を埋め込んでおく
  • フロントのJavaScriptで、選択された商品の値段を使って自動計算などの処理を行う

こんな感じで作れそうです。

では、エンティティの情報を <option> タグに持たせるにはどうすればいいでしょうか?

具体的なやり方

実は、choice_attr オプションを使えば簡単に実装できます。

こちらの過去記事 でやったこととほとんど同じですね。

具体的なコードの例は以下のような感じです。

class FooType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('item', EntityType::class, [
                'class' => Item::class,
                'label' => '商品',
                'choice_attr' => function (Item $choice, $key, $value) {
                    return [
                        'data-price' => $choice->getPrice(),
                    ];
                },
            ])
            ->add('shippingCost', NumberType::class, [
                'label' => '送料',
                'html5' => true,
            ])
        ;
    }
}

簡単ですね!

EntityTypeの場合、 choice_attr に無名関数を渡すと

  • 第1引数:エンティティのインスタンス
  • 第2引数:配列のキー( 0 始まり)
  • 第3引数:エンティティのid

を受け取れて、これらを使って <option> タグ1つ1つに任意の属性をセットすることができるのです👍

あとはフロントでちょろっとDOMをいじれば目的は果たせます。

JavaScript (jQuery)

$('#foo_item').on('change', function () {
  const price = parseInt($('#foo_item option:selected').data('price'));
  const shippingCost = price < 10000 ? 1000 : 0;
  $('#foo_shippingCost').val(shippingCost);
});

こんな感じでしょうか。

まとめ

  • SymfonyのEntityTypeでoptionタグ1つ1つにエンティティの情報を持たせてフロントから利用したい場合は、choice_attr オプションを使えば簡単にできる
GitHubで編集を提案

Discussion