Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ae5d325
UX FormCollection
stakovicz May 3, 2021
c305f0c
Remove hard coded property_name __name__
stakovicz May 4, 2021
5e6dd84
PHP CS Fixer
stakovicz May 4, 2021
eea2313
First jests
stakovicz May 4, 2021
f651d90
Rename CollectionType > UXCollectionType
stakovicz May 6, 2021
cc02076
Rename CollectionType > UXCollectionType
stakovicz May 6, 2021
dceb2cf
DependencyInjection Clean
stakovicz May 6, 2021
dfb54f8
Fix .gitattributes
stakovicz May 6, 2021
9300cda
Move default values
stakovicz May 7, 2021
ec4342a
Predefined theme or not
stakovicz May 23, 2021
b4f40cd
Update src/FormCollection/README.md
stakovicz May 24, 2021
0584757
Update src/FormCollection/README.md
stakovicz May 24, 2021
abd2b8f
Update src/FormCollection/README.md
stakovicz May 24, 2021
3996f3b
Update src/FormCollection/Resources/views/form_theme_div.html.twig
stakovicz May 24, 2021
aaa6811
Update src/FormCollection/README.md
stakovicz May 24, 2021
4791ff9
Update src/FormCollection/Resources/views/form_theme_table.html.twig
stakovicz May 24, 2021
8539ff9
Split in 4 options
stakovicz May 24, 2021
2d1ed04
Default startIndex value
stakovicz Jun 6, 2021
1e3105d
Update src/FormCollection/Resources/views/form_theme_div.html.twig
stakovicz Jul 21, 2021
0a9cc54
Update src/FormCollection/Resources/views/form_theme_div.html.twig
stakovicz Jul 21, 2021
94be94c
Update src/FormCollection/Resources/views/form_theme_table.html.twig
stakovicz Jul 21, 2021
c805c0e
Update src/FormCollection/Resources/views/form_theme_table.html.twig
stakovicz Jul 21, 2021
e56d04b
Fix coding-style-js
stakovicz Nov 6, 2021
7467cee
Prettier
stakovicz Nov 6, 2021
a8c730c
Merge branch 'symfony:2.x' into main
stakovicz Jan 19, 2022
ecd774a
Merge branch 'symfony:2.x' into main
stakovicz May 7, 2022
25d8306
Rebase and refresh the code
stakovicz May 21, 2022
8e5cd8a
fix TU
stakovicz May 21, 2022
3b110f9
change buttons attr
stakovicz May 21, 2022
c36157c
Merge branch 'symfony:2.x' into main
stakovicz Jun 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
UX FormCollection
  • Loading branch information
stakovicz committed Nov 6, 2021
commit ae5d325f12b61e2cdd20c4f7b10a42be94b7fe40
2 changes: 2 additions & 0 deletions src/FormCollection/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
37 changes: 37 additions & 0 deletions src/FormCollection/DependencyInjection/FormCollectionExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\FormCollection\DependencyInjection;

use Symfony\UX\FormCollection\Form\CollectionType;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

/**
* @internal
*/
class FormCollectionExtension extends Extension implements PrependExtensionInterface
{
public function prepend(ContainerBuilder $container)
{
}

public function load(array $configs, ContainerBuilder $container)
{
$container
->setDefinition('form.ux_collection', new Definition(CollectionType::class))
->addTag('form.type')
->setPublic(false)
;
}
}
57 changes: 57 additions & 0 deletions src/FormCollection/Form/CollectionType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\FormCollection\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType as BaseCollectionType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
* @final
* @experimental
*/
class CollectionType extends AbstractType
{
public function getParent()
{
return BaseCollectionType::class;
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'button_add' => [
'text' => 'Add',
'attr' => ['class' => 'btn btn-outline-primary'],
],
'button_delete' => [
'text' => 'Remove',
'attr' => ['class' => 'btn btn-outline-secondary'],
],
]);
}

public function finishView(FormView $view, FormInterface $form, array $options)
{
parent::finishView($view, $form, $options);

$view->vars['button_add'] = $options['button_add'];
$view->vars['button_delete'] = $options['button_delete'];
}

public function getBlockPrefix()
{
return 'form_collection';
}
}
22 changes: 22 additions & 0 deletions src/FormCollection/FormCollectionBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\UX\FormCollection;

use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
* @final
* @experimental
*/
class FormCollectionBundle extends Bundle
{
}
19 changes: 19 additions & 0 deletions src/FormCollection/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2020-2021 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
141 changes: 141 additions & 0 deletions src/FormCollection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# UX Form Collection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're now doing this as an index.rst file. So, it just needs to move, then convert to RST

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any RST files in the other parts 🤨. They are all in .md

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I had not looked in this file 😬


Symfony UX Form collection is a Symfony bundle providing light UX for collection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Symfony UX Form collection is a Symfony bundle providing light UX for collection
Symfony UX Form collection is a Symfony bundle providing JavaScript-powered "add" and "remove"
buttons to your `CollectionType` fields.

It'd be GREAT to have a little screenshot :)

in Symfony Forms.

## Installation

UX Form Collection requires PHP 7.2+ and Symfony 4.4+.

Install this bundle using Composer and Symfony Flex:

```sh
composer require symfony/ux-form-collection

# Don't forget to install the JavaScript dependencies as well and compile
yarn install --force
yarn encore dev
```

Also make sure you have at least version 2.0 of [@symfony/stimulus-bridge](https://github.com/symfony/stimulus-bridge)
in your `package.json` file.

You need to select the right theme from the one you are using :
```yaml
# config/packages/twig.yaml
twig:
# For bootstrap for example
form_themes: ['@FormCollection/form_theme_div.html.twig']
```
You have 2 different themes :
- `@FormCollection/form_theme_div.html.twig`
- `@FormCollection/form_theme_table.html.twig`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the biggest question make for me with this very nice PR. If we provide a built-in form theme to "rendering everything for them", then we will also need a Bootstrap 4/5 theme... and a tailwind theme. And, if the user needs to customize how things look, then they need to override a fairly complex form theme that we've created here.

I'm not definitely against this. However, I'd like to see if we can document how this new feature could be used if there were no form themes included. For example,

Now that your BlogFormType form set up and with a comments field that is a CollectionType, you can
render it in your template:

{% macro commentFormRow(commentForm) %}
    <div
        class="col-4"
        data-symfony--ux-form-collection--collection-target="entry"
    >
        {{ form_errors(commentForm) }}
        {{ form_row(commentForm.content) }}
        {{ form_row(commentForm.otherField) }}

        <a data-action="symfony--ux-form-collection--collection#delete">
            Remove
        </a>
    </div>
{% endblock %}

<div
    class="row"
    {{ stimulus_controller('symfony/ux-form-collection/collection', {
        prototype: _self.commentFormRow(form.comments.vars.prototype),
    }) }}
>
    {% for commentForm in form.comments %}
        {{ _self.commentFormRow(commentForm) }}
    {% endfor %}

    <a data-action="symfony--ux-form-collection--collection#add">
        Add Another
    </a>
</div>

This would give me full control over everything, including the buttons. The Stimulus controller would just handle making it all work :). The worst pieces are the super-ugly data-action and data-...-target attributes. But this would look much nicer if we merged symfony/webpack-encore-bundle#124

There may be some other missing pieces... but in theory, this should be enough to work. The "delete" button should not need a data-index-entry attribute, as we can look to its ancestors for the "closest" entry target to know which item is being removed.

So, this is my thinking :). No form theme, but we make it as dead-simple as possible for users to render things themselves.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to make a component very easy to use.
It's true that template overloading can be complicated due to attributes related to Stimulus.
With these 2 templates (@FormCollection/form_theme_div.html.twig, @FormCollection/form_theme_table.html.twig) we cover a maximum of use cases.

For your proposal, there should be explicit errors when the controller is wrong or the action is not correctly entered.

I think you need to know Stimulus to be able to set up HTML according to the documentation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make a better judgement, I'll need some time to play with this in a real project :). Would you be willing/able to push a demo app to GitHub that uses this (with some quick setup instructions)?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you have my repo for my test :
https://github.com/stakovicz/ux-collection-test/
Enjoy !

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made an update.
Now you can use a predefined theme or not.
You have the choice.

I need help to do more tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @weaverryan,

Any reason to use a macro instead of a proper form theme here?

The macro forces you to use it everywhere it's needed (eg. prototype & entries as in your example) while a "real" form theme would apply automatically to both.


[Check the Symfony doc](https://symfony.com/doc/4.4/form/form_themes.html) for the different ways to set themes in Symfony.

## Usage

The most common usage of Form Collection is to use it as a replacement of
the native CollectionType class:

```php
// ...
use Symfony\UX\FormCollection\Form\CollectionType;

class BlogFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add('comments', CollectionType::class, [
// ...
'button_add' => [
// Default text for the add button
'text' => 'Add',
// Default attr class for the add button
'attr' => ['class' => 'btn btn-outline-primary']
],
'button_delete' => [
// Default text for the delete button
'text' => 'Remove',
// Default class for the delete button
'attr' => ['class' => 'btn btn-outline-secondary']
],
])
// ...
;
}

// ...
}
```

### Extend the default behavior

Symfony UX Form Collection allows you to extend its default behavior using a custom Stimulus controller:

```js
// mycollection_controller.js

import { Controller } from 'stimulus';

export default class extends Controller {
connect() {
this.element.addEventListener('collection:pre-connect', this._onPreConnect);
this.element.addEventListener('collection:connect', this._onConnect);
this.element.addEventListener('collection:pre-add', this._onPreAdd);
this.element.addEventListener('collection:add', this._onAdd);
this.element.addEventListener('collection:pre-delete', this._onPreDelete);
this.element.addEventListener('collection:delete', this._onDelete);
}

disconnect() {
// You should always remove listeners when the controller is disconnected to avoid side effects
this.element.removeEventListener('collection:pre-connect', this._onPreConnect);
this.element.removeEventListener('collection:connect', this._onConnect);
}

_onPreConnect(event) {
// The collection is not yet connected
console.log(event.detail.allowAdd); // Access to the allow_add option of the form
console.log(event.detail.allowDelete); // Access to the allow_delete option of the form
}

_onConnect(event) {
// Same as collection:pre-connect event
}

_onPreAdd(event) {
console.log(event.detail.index); // Access to the curent index will be added
console.log(event.detail.element); // Access to the element will be added
}

_onAdd(event) {
// Same as collection:pre-add event
}

_onPreDelete(event) {
console.log(event.detail.index); // Access to the index will be removed
console.log(event.detail.element); // Access to the elemnt will be removed
}

_onDelete(event) {
// Same as collection:pre-delete event
}
}
```

Then in your render call, add your controller as an HTML attribute:

```php
$builder
// ...
->add('comments', UXCollectionType::class, [
// ...
'attr' => [
// Change the controller name
'data-controller' => 'mycollection'
]
]);
```
4 changes: 4 additions & 0 deletions src/FormCollection/Resources/assets/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"presets": ["@babel/env"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
1 change: 1 addition & 0 deletions src/FormCollection/Resources/assets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/node_modules/
Loading