SymfonyのCollectionType
entry_type
各項目のFormTypeを指定
allow_add
fieldの個数を可変にできる
allow_delete
fieldの削除をできるようにする
prototype
allow_addを使うときに使う
プロトタイプの出力できるようにする
prototype_data
CollectionTypeにはdataというoptionがないということに注意mrsekut.icon*3
代わりにprototype_dataを使う
空フォームの初期値にここの値が入る
fieldの個数を指定できるわけではないmrsekut.icon
porototype_dataを指定しない場合は、entry_options内のdataが初期値として入る
Collectionする対象がTextTypeのときとかはdocsに書いてるけど、
対象もCollectionTypeのときの初期値の設定の仕方がわからん #?? とりあえず動くコード
ここに載っているコード、無駄に複雑に書かれているのであまり参考にしすぎない方がいい code:php
# form builder内
$builder->add('hoges', CollectionType::class, [
'entry_type' => EmailType::class,
'entry_options' => [
],
'label' => false,
'allow_add' => true,
'allow_delete' => true,
'prototype' => true,
'mapped' => false
]);
code:js
$('.add-another-collection-widget').on('click', function (event) {
const ul = $('#email-fields-list');
const count = ul.data('counter') || ul.children().length;
const newField = ul.attr('data-prototype').replace(/__name__/g, count+1);
ul.append(newField);
ul.data('counter', count+1);
});
code:twig(php)
<ul id="email-fields-list"
data-counter="{{ form.hoges|length }}"
data-prototype="
{% filter escape %}
{% import _self as field %}
{{field.field(form.hoges.vars.prototype)}}
{% endfilter %}">
</ul>
<button type="button" class="add-another-collection-widget">
add field
</button>
{% macro field(fields) %}
<li>
// {% set index = fields.vars.name %} indexはこれでアクセスできる
// 子がいるときはfields.piyoみたいに書く
{{ form_widget(fields) }}
{{ form_errors(fields) }}
</li>
{% endmacro %}
count保持してないと削除や追加を繰り返すとindexが重複してしまう
初回ではfieldに値がない場合はrenderingされない
データが無のときは追加ボタンしか表示されない ref https://gyazo.com/2045a5e15290281ae16f59a2bc3b5ad5
ボタンを押して追加するとformが表示される
https://gyazo.com/d585aedb970368b65ccdcaecf29f9ac5
なんでこんな仕様やねんmrsekut.icon
form 0個にすることほぼないやろ
この仕様のせいで、add_allowやprototypeがfalseのときは実質的に何もrenderingされないことになってしまう
初回からfieldを表示するには以下のいずれかで対応する
CollectionTypeの定義時にdataoptionを指定する
ControllerかjQueryで「dataが無のときはfieldを追加する」のような処理を書く
code:ex.js
// 上に書いてるfield追加ボタンロジックに少し手を加える
$(function () {
const ul = $('#email-fields-list');
const count = ul.children().length;
if(count === 0){
const newField = ul.attr('data-prototype').replace(/__name__/g, 1);
ul.append(newField);
}
});
formのpairのCollectionとかできないのか #?? できるよmrsekut.icon
pairのfieldを、HogeTypeという形でformを作っておく
code:php
class HogeType extends AbstractType {
/**
* {@inheritdoc}
*/
function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('hoge', TextType::class, [])
->add('piyo', NumberType::class, []);
}
..
それをCollectionTypeに渡せばいい
code:php
$builder
->add('hoges', CollectionType::class, [
'entry_type' => HogeType::class,
...
そしたら追加ボタンを押すたびに2つのfieldが追加されるようになる
可変でなく固定にしたい場合
Collectionとして扱いたいが、3個固定で表示したい、というときもある
その場合「追加ボタン」は不要である
上記のような問題により、ただこれを書くだけでは何もrenderingされない
Controllerか、jQueryからで「データが3個未満の場合は、emptyを埋める」みたいな処理を書く必要がある
loopで表示する
code:twig
{% for field in form.hoges %}
<li>
{{ form_errors(field) }}
{{ form_widget(field) }}
</li>
{% endfor %}
validation時に、他のfieldの値を参照したい時
add_allowの有無に関わらずjQeuryの記述が必要なのか
別にそんな琴無い
docsのここに書いてるのは、「追加ボタンをクリックしたらformを増やす」という処理であって、renderingには関係ない add_allowをfalseにしてrenderingさせることは実質的に不可能ってことか
add_allow:falseはHiddenTypeと併用するときにのみに使うんかな
prototypeってなに?
例とか