ngx-formly icon indicating copy to clipboard operation
ngx-formly copied to clipboard

Bootstrap 5 floating labels

Open mdantonio opened this issue 4 years ago • 18 comments

Question

Following the suggestion in #2603 I tried to define a custom wrapper to implement floating labels as introduced with bootstrap 5, but i can't get it to work

The template is pretty simple

    <div class="form-floating mb-3">
      <ng-template #fieldComponent></ng-template>
      <div *ngIf="showError" class="invalid-feedback" [style.display]="'block'">
        <formly-validation-message [field]="field"></formly-validation-message>
      </div>

      <label
        [attr.for]="id"
        class="col-form-label col-form-label-sm"
        *ngIf="to.label">
        {{ to.label }}
        <ng-container *ngIf="to.required && to.hideRequiredMarker !== true"
          >*</ng-container
        >
      </label>
    </div>

or even simplified is:

    <div class="form-floating mb-3">
      <ng-template #fieldComponent></ng-template>

      <label
        [attr.for]="id"
        class="col-form-label"
        *ngIf="to.label">
        {{ to.label }}
      </label>
    </div>

The problem that I found is that <ng-template #fieldComponent> wraps the input field with a formly-field-input element producing an html like:

<div class="form-floating mb-3">
    <formly-field-input>
        <input ... />
    </formly-field-input>

    <label for...>
        MyLabel
    </label>
</div>

And this is not accepted by bootstrap, that requires both input and label to be direct children of the .form-floating div

This is the css extracted from bootstrap:

.form-floating {
  position: relative;

  > .form-control,
  > .form-select {
    height: $form-floating-height;
    line-height: $form-floating-line-height;
  }

  > label {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%; // allow textareas
    padding: $form-floating-padding-y $form-floating-padding-x;
    pointer-events: none;
    border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model
    transform-origin: 0 0;
    @include transition($form-floating-transition);
  }

Could you suggest me how to properly set this template?

And on a more general sense: is there any plan to support floating labels directly in formly?

Thank you for your help!

mdantonio avatar Apr 11 '22 12:04 mdantonio

And on a more general sense: is there any plan to support floating labels directly in formly?

Sure, no one requested it before.

Could you suggest me how to properly set this template?

Could you please replicate what you've done using stackblitz in order to check it on my side.

Thank you!

aitboudad avatar Apr 13 '22 06:04 aitboudad

Here a stackblitz with the template https://ngx-formly-ui-bootstrap-jm5wke.stackblitz.io

I also added the corresponding html form for comparison convenience

mdantonio avatar Apr 13 '22 07:04 mdantonio

you may need to adjust floating-labels to take account of nested selector, here is a quick attempt https://stackblitz.com/edit/ngx-formly-ui-bootstrap-ufagnu

aitboudad avatar Apr 13 '22 08:04 aitboudad

Thank you for that! This confirms the problem with the bootstrap css.

Do you think that formly would be somehow able to produce an html compliant with the bootstrap expectations? Based on my understanding, the fieldComponent should be able to embed the label to nest both input and label into the same element... is this feasible?

mdantonio avatar Apr 13 '22 13:04 mdantonio

Hello, I was playing a bit more with this by doing some additional tests. I tried to add an addonLeft, but in this case the rendering of both the addonLeft icon/text overlaps with a bad result. It seems like having a smooth integration is even more complicated than that :disappointed:

mdantonio avatar May 01 '22 06:05 mdantonio

Do you think that formly would be somehow able to produce an html compliant with the bootstrap expectations?

Yes possible.

aitboudad avatar May 10 '22 21:05 aitboudad

This issue has been fixed and released as part of v6.0.0-beta.0 release. To use floating label, pass floating to labelPosition property.

Please let us know, in case you are still encountering a similar issue/problem. Thank you!

aitboudad avatar May 22 '22 18:05 aitboudad

It works very well, thank you! :smiley:

But it seems to be not compatible with addon icons :cry:

Is there any way to set both floating labels and addon icons?

For example this is ok:

        templateOptions: {
          type: "email",
          label: "Username",
          labelPosition: "floating"
       }

=>

Screenshot from 2022-05-28 09-43-12

but this is not:

        templateOptions: {
          type: "email",
          label: "Username",
          labelPosition: "floating",
          addonLeft: {
            class: "fas fa-envelope",
          }
       }

=>

Screenshot from 2022-05-28 09-43-50

Thank you!

mdantonio avatar May 28 '22 07:05 mdantonio

https://github.com/twbs/bootstrap/issues/34513

aitboudad avatar May 28 '22 07:05 aitboudad

Thank you

mdantonio avatar May 28 '22 08:05 mdantonio

Sorry to bother you again, I was trying to apply floating labels also to custom fields, but mostly failed.

Is there any example on the documentation to start from?

I tried to add the

<ng-template #fieldTypeTemplate>

that I see you added with https://github.com/ngx-formly/ngx-formly/pull/3304, but it seems to be not enough :pray:

mdantonio avatar Jun 04 '22 08:06 mdantonio

- import { FieldType } from '@ngx-formly/core';
+ import { FieldType } from '@ngx-formly/bootstrap/form-field';

aitboudad avatar Jun 04 '22 09:06 aitboudad

I found the problem with my custom template: I have a constructor to inject a service into the component. This works with FieldType from core, but not from bootstrap/form-field

If I add something like:

  constructor(private myCustomService) {
    super();
  }

the field disappears. I see that the constructor on the bootstrap version accepts an Optional ViewContainerRef that the core hasn't, should I pass something?

Here a stackblitz with some tests, including a custom field (but with the constructor commented out) https://stackblitz.com/edit/ngx-formly-ui-bootstrap-ssmmr5?file=src/app/formly.custom.component.ts

mdantonio avatar Jun 05 '22 05:06 mdantonio

passing ViewContainerRef is required in case you need to inject extra service in your custom component:

constructor(private myCustomService, containerRef: ViewContainerRef) {
  super(containerRef);
}

aitboudad avatar Jun 05 '22 09:06 aitboudad

Thank you!

mdantonio avatar Jun 05 '22 12:06 mdantonio

https://github.com/twbs/bootstrap/issues/34513

Issue closed and released with bootstrap 5.2 🚀

Is the support for addon icons + floating labels expected to be "automatically working" on formly or some changes on your side would be needed? I tried today with bootstrap 5.2 but I can't see large difference 🤔

mdantonio avatar Jul 24 '22 07:07 mdantonio

Is the support for addon icons + floating labels expected to be "automatically working" on formly

I think so

aitboudad avatar Jul 24 '22 16:07 aitboudad

Tried on stackblitz with bootstrap 5.2+ but with no luck 😢

https://stackblitz.com/edit/ngx-formly-ui-bootstrap-jm5wke

Something wrong on my side?

Thank you for your precious help! 🙏

mdantonio avatar Jul 30 '22 08:07 mdantonio