Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Form] Improve rendering of file field in bootstrap 4 #27919

Merged
merged 1 commit into from Jul 15, 2018
Merged

[Form] Improve rendering of file field in bootstrap 4 #27919

merged 1 commit into from Jul 15, 2018

Conversation

apfelbox
Copy link
Contributor

@apfelbox apfelbox commented Jul 10, 2018

Q A
Branch? 4.1+
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets
License MIT
Doc PR

Hi 👋

currently adding a file type to a form looks weird in the bootstrap 4 form themes:

$builder
    ->add("pdfFile", FileType::class, [
        "label" => "PDF",
    ]);

Before

Vertical Form

2018-07-10 at 21 36

Horizontal Form

2018-07-10 at 21 37

After

Vertical Form

2018-07-10 at 21 38

Horizontal Form

2018-07-10 at 21 38

Things to consider

There are three labels here:

2018-07-10 at 21 40

  1. the actual field label. Here the $options["label"] is used.
  2. the placeholder. Here $options["attr"]["placeholder"] ?? "" is used new
  3. the label on the button. This is set in CSS actually, on an ::after attribute.

There isn't much we can do about 3) because there is no inline HTML-way to overwrite the style of a pseudo element. So if the app developer wants to have localization in this field as well, (s)he has to set it in their CSS file as described in the bootstrap docs

Todo

  • WIP because I haven't managed to get the test suite to run locally yet, so we will debug with Travis 🙌  okay, getting them to work is really, really easy, but you just have to get over yourself and do it 🙄

@apfelbox apfelbox changed the title [WIP][Form] Improve rendering of file field in bootstrap 4 [Form] Improve rendering of file field in bootstrap 4 Jul 10, 2018
$this->assertWidgetMatchesXpath($form->createView(), array('attr' => array('class' => 'my&class form-control-file')),
'/input
[@type="file"]
$this->assertWidgetMatchesXpath($form->createView(), array('id' => 'nope', 'attr' => array('class' => 'my&class form-control-file')),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I know that this id-thing here is weird, but the check doesn't make sense for this file type (because of the special structure), I guess.

@xabbuh
Copy link
Member

xabbuh commented Jul 11, 2018

WIll this fix #27477?

@apfelbox
Copy link
Contributor Author

apfelbox commented Jul 11, 2018

@xabbuh unfortunately not ... that doesn't even work in their own docs in the examples: https://getbootstrap.com/docs/4.0/components/forms/#file-browser

So imo we have two choices regarding #27477

1. Say that the user has to do it themselves

Just like they need to load the CSS by themselves, they would need to write some JS as integration code here. We can maybe make it easier for them by adding a hint in the docs with example code.

2. add the JS functionality with a possibility to opt-out

Opt-out because inline JS and CSP don't mix and because somebody doesn't want custom JS in their app (not sure whether Symfony 2+ ever injected JS somewhere else besides the toolbar).

Would look something like this:

{% block file_widget -%}
    <div class="form-group">
        ...
    </div>
    <script type="text/javascript">
        (function (document) {
            var input = document.getElementById("{{form.vars.id}}");
            var placeholder = input.parentElement.querySelector("custom-file-label.");

            input.addEventListener(
                "change",
                function ()
                {
                    var value = input.value.replace('C:\\fakepath\\', '').trim();
                    placeholder.textContent = "" !== value ? value : (input.getAttribute('placeholder') || '');
                }
            );
        })(document);
    </script>
{% endblock %}

if we want to set it directly on each field or add some JS at the end of the form that does the same thing.
I can send a PR for it either way, we just need to decide.

@apfelbox
Copy link
Contributor Author

This issue right here is only for fixing the styling of the form row containing the file field.

@vudaltsov
Copy link
Contributor

This should be for 3.4 since it's a bug, I guess?

Copy link
Contributor

@vudaltsov vudaltsov left a comment

Choose a reason for hiding this comment

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

With these changes we'll have 2 <label> tags for this field, which is not appropriate according to this stackoverflow answer. We can have <legend> for the first one, WDYT?

@apfelbox
Copy link
Contributor Author

@vudaltsov the file field in the bootstrap 4 Theme was added in 4.1.

@apfelbox
Copy link
Contributor Author

@vudaltsov I am afraid that you read the StackOverflow answer wrong..

Here is what I read there:

Each LABEL element is associated with exactly one form control.

One label can only have one input.

[...] each form control can be referenced by multiple labels [...]

One input can have multiple labels.

We fall in the second category.
Using a <label> is quite important here, as we need the functionality, that a click on the label focuses the input field and therefore opens the browser file selector. That automatic focusing is key and doesn't work with a <legend>.

@vudaltsov
Copy link
Contributor

Great! I was wrong. Thank you for explanations 👍

@fabpot
Copy link
Member

fabpot commented Jul 15, 2018

Thank you @apfelbox.

@fabpot fabpot merged commit 32ad5d9 into symfony:4.1 Jul 15, 2018
fabpot added a commit that referenced this pull request Jul 15, 2018
…pfelbox)

This PR was squashed before being merged into the 4.1 branch (closes #27919).

Discussion
----------

[Form] Improve rendering of `file` field in bootstrap 4

| Q             | A
| ------------- | ---
| Branch?       | 4.1+
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | —
| License       | MIT
| Doc PR        | —

Hi 👋

currently adding a file type to a form looks weird in the bootstrap 4 form themes:

```php
$builder
    ->add("pdfFile", FileType::class, [
        "label" => "PDF",
    ]);
```

## Before

### Vertical Form

![2018-07-10 at 21 36](https://user-images.githubusercontent.com/1032411/42533175-6b88e33a-8489-11e8-927a-8e987f362913.png)

### Horizontal Form

![2018-07-10 at 21 37](https://user-images.githubusercontent.com/1032411/42533197-7d45944c-8489-11e8-970f-79b18a273366.png)

## After

### Vertical Form

![2018-07-10 at 21 38](https://user-images.githubusercontent.com/1032411/42533229-8ebe44a8-8489-11e8-94e0-891403063476.png)

### Horizontal Form

![2018-07-10 at 21 38](https://user-images.githubusercontent.com/1032411/42533247-99782db4-8489-11e8-9f66-30a5dccdaa9d.png)

## Things to consider

There are three labels here:

![2018-07-10 at 21 40](https://user-images.githubusercontent.com/1032411/42533370-ecbaf63c-8489-11e8-9be8-1c8c3342c459.png)

1) the actual field label. Here the `$options["label"]` is used.
2) the placeholder. Here `$options["attr"]["placeholder"] ?? ""` is used **new**
3) the label on the button. This is set in CSS actually, on an `::after` attribute.

There isn't much we can do about 3) because there is no inline HTML-way to overwrite the style of a pseudo element. So if the app developer wants to have localization in this field as well, (s)he has to set it in their CSS file [as described in the bootstrap docs](https://getbootstrap.com/docs/4.0/components/forms/#file-browser)

## Todo

- [x] ~~WIP because I haven't managed to get the test suite to run locally yet, so we will debug with Travis 🙌~~  okay, getting them to work is really, really easy, but you just have to get over yourself and do it 🙄

Commits
-------

32ad5d9 [Form] Improve rendering of `file` field in bootstrap 4
@apfelbox apfelbox deleted the bootstrap-file-field-styling branch July 15, 2018 15:38
@apfelbox
Copy link
Contributor Author

@fabpot thanks for the merge!
I forgot to add something, so there is a follow-up PR in #27958 😞

fabpot added a commit that referenced this pull request Jul 16, 2018
…lbox)

This PR was merged into the 4.1 branch.

Discussion
----------

[Form] Remaining changes for bootstrap 4 file fields

| Q             | A
| ------------- | ---
| Branch?       | 4.1
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no>
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | —
| License       | MIT
| Doc PR        | —

Hi again,

This is a follow-up PR for #27919

Apparently I talked about it in the previous PR, but forgot to actually push the change. Sorry about that! 😞

This PR no actually adds this instead of just talking about it:

![2018-07-15 at 17 52](https://user-images.githubusercontent.com/1032411/42735630-e19b22be-8857-11e8-85b8-6d64e17c2be2.png)

Sorry again, just forgot to actually update the last PR.

Commits
-------

3cd2eef Add placeholder support in bootstrap 4 file fields
nicolas-grekas pushed a commit to nicolas-grekas/symfony that referenced this pull request Jul 23, 2018
…ap 4 (apfelbox)

This PR was squashed before being merged into the 4.1 branch (closes symfony#27919).

Discussion
----------

[Form] Improve rendering of `file` field in bootstrap 4

| Q             | A
| ------------- | ---
| Branch?       | 4.1+
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | —
| License       | MIT
| Doc PR        | —

Hi 👋

currently adding a file type to a form looks weird in the bootstrap 4 form themes:

```php
$builder
    ->add("pdfFile", FileType::class, [
        "label" => "PDF",
    ]);
```

## Before

### Vertical Form

![2018-07-10 at 21 36](https://user-images.githubusercontent.com/1032411/42533175-6b88e33a-8489-11e8-927a-8e987f362913.png)

### Horizontal Form

![2018-07-10 at 21 37](https://user-images.githubusercontent.com/1032411/42533197-7d45944c-8489-11e8-970f-79b18a273366.png)

## After

### Vertical Form

![2018-07-10 at 21 38](https://user-images.githubusercontent.com/1032411/42533229-8ebe44a8-8489-11e8-94e0-891403063476.png)

### Horizontal Form

![2018-07-10 at 21 38](https://user-images.githubusercontent.com/1032411/42533247-99782db4-8489-11e8-9f66-30a5dccdaa9d.png)

## Things to consider

There are three labels here:

![2018-07-10 at 21 40](https://user-images.githubusercontent.com/1032411/42533370-ecbaf63c-8489-11e8-9be8-1c8c3342c459.png)

1) the actual field label. Here the `$options["label"]` is used.
2) the placeholder. Here `$options["attr"]["placeholder"] ?? ""` is used **new**
3) the label on the button. This is set in CSS actually, on an `::after` attribute.

There isn't much we can do about 3) because there is no inline HTML-way to overwrite the style of a pseudo element. So if the app developer wants to have localization in this field as well, (s)he has to set it in their CSS file [as described in the bootstrap docs](https://getbootstrap.com/docs/4.0/components/forms/#file-browser)

## Todo

- [x] ~~WIP because I haven't managed to get the test suite to run locally yet, so we will debug with Travis 🙌~~  okay, getting them to work is really, really easy, but you just have to get over yourself and do it 🙄

Commits
-------

32ad5d9 [Form] Improve rendering of `file` field in bootstrap 4
nicolas-grekas pushed a commit to nicolas-grekas/symfony that referenced this pull request Jul 23, 2018
…s (apfelbox)

This PR was merged into the 4.1 branch.

Discussion
----------

[Form] Remaining changes for bootstrap 4 file fields

| Q             | A
| ------------- | ---
| Branch?       | 4.1
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no>
| Tests pass?   | yes    <!-- please add some, will be required by reviewers -->
| Fixed tickets | —
| License       | MIT
| Doc PR        | —

Hi again,

This is a follow-up PR for symfony#27919

Apparently I talked about it in the previous PR, but forgot to actually push the change. Sorry about that! 😞

This PR no actually adds this instead of just talking about it:

![2018-07-15 at 17 52](https://user-images.githubusercontent.com/1032411/42735630-e19b22be-8857-11e8-85b8-6d64e17c2be2.png)

Sorry again, just forgot to actually update the last PR.

Commits
-------

3cd2eef Add placeholder support in bootstrap 4 file fields
@fabpot fabpot mentioned this pull request Jul 23, 2018
@MrMitch
Copy link

MrMitch commented Aug 1, 2018

Hi @apfelbox, thank you for this and #27958. I just updated to Symfony 4.1.3 in the hope of using it but I still see the 4.1.1 behavior : no label above the field.

In my case the code

$builder->add('name', TextType::class, [
    'label' => 'Nom du partenaire'
])
->add('image', FileType::class, [
    'label' => 'LABEL',
    'attr' => ['placeholder' => 'PLACEHOLDER'],
    'mapped' => false,
]);

renders the following form :
image

Looking at the source code in my vendor/symfony/twig-bridge/Resouces/views/Form folder does show your version of the code, so I was wondering if there might have been something between 4.1.2 and 4.1.3 that affected the rendering of FileType widget ?

@apfelbox
Copy link
Contributor Author

apfelbox commented Aug 2, 2018

Hmm, not that I know of, so it should work.

Do you have any custom form themes loaded and how do you render the form in your template?

@MrMitch
Copy link

MrMitch commented Aug 2, 2018

After further investigation, it looks like something was wrong with my symfony installation.

The toolbar was reporting 4.1.3 :
image

but most of the pakages were still on 4.1.1 :

$ composer update --dry-run
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 3 installs, 47 updates, 0 removals
  - Updating symfony/flex (v1.0.80) to symfony/flex (v1.0.89)
  - Updating symfony/dotenv (v4.1.1) to symfony/dotenv (v4.1.3)
  - Updating symfony/expression-language (v4.1.1) to symfony/expression-language (v4.1.3)
  - Updating symfony/inflector (v4.1.1) to symfony/inflector (v4.1.3)
  - Updating symfony/property-access (v4.1.1) to symfony/property-access (v4.1.3)
  - Updating symfony/options-resolver (v4.1.1) to symfony/options-resolver (v4.1.3)
  - Updating symfony/intl (v4.1.1) to symfony/intl (v4.1.3)
  - Updating symfony/form (v4.1.1) to symfony/form (v4.1.3)
  - Updating symfony/routing (v4.1.1) to symfony/routing (v4.1.3)
  - Updating symfony/finder (v4.1.1) to symfony/finder (v4.1.3)
  - Updating symfony/framework-bundle (v4.1.1) to symfony/framework-bundle (v4.1.3)
  - Updating symfony/phpunit-bridge (v4.1.1) to symfony/phpunit-bridge (v4.1.3)
  - Updating symfony/property-info (v4.1.1) to symfony/property-info (v4.1.3)
  - Updating symfony/security (v4.1.1) to symfony/security (v4.1.3)
  - Updating symfony/security-bundle (v4.1.1) to symfony/security-bundle (v4.1.3)
  - Updating twig/twig (v2.4.8) to twig/twig (v2.5.0)
  - Updating symfony/twig-bridge (v4.1.1) to symfony/twig-bridge (v4.1.3)
  - Updating symfony/twig-bundle (v4.1.1) to symfony/twig-bundle (v4.1.3)
  - Updating symfony/translation (v4.1.1) to symfony/translation (v4.1.3)
  - Updating symfony/validator (v4.1.1) to symfony/validator (v4.1.3)
  - Updating symfony/web-link (v4.1.1) to symfony/web-link (v4.1.3)
  - Updating symfony/asset (v4.1.1) to symfony/asset (v4.1.3)
  - Updating symfony/webpack-encore-pack (v1.0.2) to symfony/webpack-encore-pack (v1.0.3)
  - Updating sebastian/comparator (3.0.1) to sebastian/comparator (3.0.2)
  - Updating phar-io/version (1.0.1) to phar-io/version (2.0.1)
  - Updating phar-io/manifest (1.0.1) to phar-io/manifest (1.0.3)
  - Updating phpunit/phpunit (7.2.6) to phpunit/phpunit (7.2.7)
  - Updating symfony/dom-crawler (v4.1.1) to symfony/dom-crawler (v4.1.3)
  - Updating symfony/browser-kit (v4.1.1) to symfony/browser-kit (v4.1.3)
  - Updating symfony/css-selector (v4.1.1) to symfony/css-selector (v4.1.3)
  - Updating symfony/process (v4.1.1) to symfony/process (v4.1.3)
  - Updating symfony/console (v4.1.1) to symfony/console (v4.1.3)
  - Updating symfony/web-server-bundle (v4.1.1) to symfony/web-server-bundle (v4.1.3)
  - Updating symfony/yaml (v4.1.1) to symfony/yaml (v4.1.3)
  - Updating easycorp/easy-log-handler (v1.0.5) to easycorp/easy-log-handler (v1.0.7)
  - Updating symfony/var-dumper (v4.1.1) to symfony/var-dumper (v4.1.3)
  - Updating symfony/debug-bundle (v4.1.1) to symfony/debug-bundle (v4.1.3)
  - Updating symfony/monolog-bridge (v4.1.1) to symfony/monolog-bridge (v4.1.3)
  - Updating symfony/stopwatch (v4.1.1) to symfony/stopwatch (v4.1.3)
  - Updating symfony/web-profiler-bundle (v4.1.1) to symfony/web-profiler-bundle (v4.1.3)
  - Updating nikic/php-parser (v4.0.2) to nikic/php-parser (v4.0.3)
  - Installing doctrine/reflection (v1.0.0)
  - Installing doctrine/event-manager (v1.0.0)
  - Installing doctrine/persistence (v1.0.0)
  - Updating doctrine/common (v2.8.1) to doctrine/common (v2.9.0)
  - Updating doctrine/dbal (v2.7.1) to doctrine/dbal (v2.8.0)
  - Updating doctrine/orm (v2.6.1) to doctrine/orm (v2.6.2)
  - Updating symfony/serializer (v4.1.1) to symfony/serializer (v4.1.3)
  - Updating swiftmailer/swiftmailer (v6.1.1) to swiftmailer/swiftmailer (v6.1.2)
  - Updating symfony/doctrine-bridge (v4.1.1) to symfony/doctrine-bridge (v4.1.3)

Running composer update fixed everything, and my form now renders properly.
Sorry about the false-positive, thank you for your quick reply !

@MrMitch
Copy link

MrMitch commented Aug 2, 2018

@apfelbox a quick follow-up : I noticed that the .custom-file element in wrapped in an extra div.form-group in the file_widget block :

{% block file_widget -%}
    {# this is the wrapper i'm talking about #}
    <div class="form-group">
        <{{ element|default('div') }} class="custom-file">
            {%- set type = type|default('file') -%}
            {{- block('form_widget_simple') -}}
            <label for="{{ form.vars.id }}" class="custom-file-label">
                {%- if attr.placeholder is defined -%}
                    {{- translation_domain is same as(false) ? attr.placeholder : attr.placeholder|trans({}, translation_domain) -}}
                {%- endif -%}
            </label>
        </{{ element|default('div') }}>
    </div>
{% endblock %}

In bootstrap, the .form-group has a bottom margin.

So when the form_row(form.my_file) function is used, the label is followed by a div.form-group and the help text is rendered after this div.form-group. Because of this, the help text on file widgets is further away from the control than on other widgets:

image

(this might be easier to see without the Chrome console info)
image

@apfelbox
Copy link
Contributor Author

apfelbox commented Aug 2, 2018

@MrMitch ahaha, you were faster than me 😉
Thanks for your investigation, though

nicolas-grekas added a commit that referenced this pull request Aug 7, 2018
… in bootstrap 4 (MrMitch)

This PR was merged into the 4.1 branch.

Discussion
----------

[Form] Remove extra .form-group wrapper around file widget in bootstrap 4

| Q             | A
| ------------- | ---
| Branch?       | 4.1
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        |  n/a

This is a follow-up to #27958 and #27919 by @apfelbox .

It fixes an extra space between the help text of a FileType widget and the widget itself. The extra space was caused by a `.form-group` wrapper in the `file_widget` block.

Commits
-------

01e7fe4 [Form] Remove extra .form-group wrapper around file widget in bootstrap 4
symfony-splitter pushed a commit to symfony/twig-bridge that referenced this pull request Aug 7, 2018
…ap 4

This is a follow-up to symfony/symfony#27958 and
symfony/symfony#27919.

It fixes an extra space between the help text of a FileType widget and the
widget itself. The extra space was cause by a .form-group wrapper in the
file_widget block.
@Pesulap
Copy link

Pesulap commented Feb 6, 2019

It works in my project
function getoutput(){ var value = $("#imputID").val().replace('C:\\fakepath\\', '').trim();$("#imputID").next(".custom-file-label").html(value);}
and
input has attribute onChange="getoutput()"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants