@@ -1220,6 +1220,106 @@ When the user clicks ``removeComment()``, a similar process happens.
12201220 attribute above the ``Post.comments `` property. These help new
12211221 items save and deletes any items whose embedded forms are removed.
12221222
1223+ Using LiveCollectionType
1224+ ~~~~~~~~~~~~~~~~~~~~~~~~
1225+
1226+ .. versionadded :: 2.2
1227+
1228+ The ``LiveCollectionType `` and the ``LiveCollectionTrait `` was added in LiveComponent 2.2.
1229+
1230+
1231+ The ``LiveCollectionType `` uses the same method described above, but in
1232+ a generic way, so it needs even less code. This form type adds an 'Add'
1233+ and a 'Delete' button for each row by default, which work out of the box
1234+ thanks to the ``LiveCollectionTrait ``.
1235+
1236+ Let's take the same example as before, a "Blog Post" form with an embedded "Comment" forms
1237+ via the ``LiveCollectionType ``::
1238+
1239+ namespace App\Form;
1240+
1241+ use Symfony\Component\Form\AbstractType;
1242+ use Symfony\Component\Form\FormBuilderInterface;
1243+ use Symfony\Component\OptionsResolver\OptionsResolver;
1244+ use Symfony\UX\LiveComponent\Form\Type\LiveCollectionType;
1245+ use App\Entity\BlogPost;
1246+
1247+ class BlogPostFormType extends AbstractType
1248+ {
1249+ public function buildForm(FormBuilderInterface $builder, array $options)
1250+ {
1251+ $builder
1252+ ->add('title', TextType::class)
1253+ // ...
1254+ ->add('comments', LiveCollectionType::class, [
1255+ 'entry_type' => CommentFormType::class,
1256+ 'allow_add' => true,
1257+ 'allow_delete' => true,
1258+ 'by_reference' => false,
1259+ ])
1260+ ;
1261+ }
1262+
1263+ public function configureOptions(OptionsResolver $resolver)
1264+ {
1265+ $resolver->setDefaults(['data_class' => BlogPost::class]);
1266+ }
1267+ }
1268+
1269+ Now, create a Twig component to render the form::
1270+
1271+ namespace App\Twig;
1272+
1273+ use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1274+ use Symfony\Component\Form\FormInterface;
1275+ use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
1276+ use Symfony\UX\LiveComponent\DefaultActionTrait;
1277+ use Symfony\UX\LiveComponent\LiveCollectionTrait;
1278+ use App\Entity\BlogPost;
1279+ use App\Form\BlogPostFormType;
1280+
1281+ #[AsLiveComponent('blog_post_collection_type')]
1282+ class BlogPostCollectionTypeComponent extends AbstractController
1283+ {
1284+ use LiveCollectionTrait;
1285+ use DefaultActionTrait;
1286+
1287+ #[LiveProp]
1288+ public BlogPost $post;
1289+
1290+ protected function instantiateForm(): FormInterface
1291+ {
1292+ return $this->createForm(BlogPostFormType::class, $this->post);
1293+ }
1294+ }
1295+
1296+ There is no need for a custom template just render the form as usual:
1297+
1298+ .. code-block :: twig
1299+
1300+ <div {{ attributes }} data-action="change->live#update">
1301+ {{ form(form) }}
1302+ </div>
1303+
1304+ The ``add `` and ``delete `` buttons rendered as separate ``ButtonType `` form
1305+ types and can be customized like a normal form type via the ``live_collection_button_add ``
1306+ and ``live_collection_button_delete `` respectively:
1307+
1308+ .. code-block :: twig
1309+
1310+ {% block live_collection_button_add_widget %}
1311+ {% set attr = attr|merge({'class': attr.class|default('btn btn-ghost')}) %}
1312+ {% set translation_domin = false %}
1313+ {% set label_html = true %}
1314+ {%- set label -%}
1315+ <svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
1316+ <path stroke-linecap="round" stroke-linejoin="round" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
1317+ </svg>
1318+ {{ 'form.collection.button.add.label'|trans({}, 'forms') }}
1319+ {%- endset -%}
1320+ {{ block('button_widget') }}
1321+ {% endblock live_collection_button_add_widget %}
1322+
12231323 Modifying Embedded Properties with the "exposed" Option
12241324-------------------------------------------------------
12251325
0 commit comments