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

Formly + ngx mask - label not floating when initial input value is set #1305

Open
Johnnyboy7781 opened this issue Feb 2, 2024 · 6 comments

Comments

@Johnnyboy7781
Copy link

🐞 bug report

Is this a regression?

Unsure

Description

I have an Angular app (using the standalone API) that uses ngx-formly for creating forms. I am currently adding ngx-mask to be used in masking user input. I have created a custom ngx-formly component type that implements ngx-mask called 'masked-input'. This component type is simply a mat-form-field with a mat-label and an input (which uses the MatInput class).

Everything seems to work as expected until I set an initial value with defaultValue. When I have this set, the label and value will be overlapping like the following example:

image

Clicking the input will cause the label to behave normally again.

What I've Tried

Change Detection
Initially felt like a change detection issue. I've tried changing detection strategy to OnPush and virtually no change. I've also tried calling markForCheck() and detectChanges() at various points in the component's lifecycle to no avail. I tried wrapping markForCheck() in a setTimeout with a 0 second delay in my ngOnInit() which actually worked! Though, this feels like a hack and is not a solution I would like to actually ship.

Input Attributes
I've tried removing and adding attributes on the input element to see where exactly it breaks. The issue begins the moment I add the mask attribute. I also played around with the value attribute a bit. I found that I could provide it with a default value of just a space, value=" ", and that would also cause the problem to go away. Though, again this feels like a hack and not something I feel comfortable shipping if there is a better way.

provideAnimations()
I noticed while playing around with the StackBlitz demo that the label will behave normally if I remove the call to provideAnimations() in the bootstrapApplication() call, though I would begin to get a ton of errors in the console. Maybe that is at least a clue?

🔬 Minimal Reproduction

https://stackblitz.com/edit/stackblitz-starters-u7zpzf?file=src%2Fmain.ts

🔥 Exception or Error

None

🌍 Your Environment

My app runs on the following:

"@angular-architects/module-federation": "^16.0.4",
"@angular/animations": "^16.2.0",
"@angular/common": "^16.2.0",
"@angular/compiler": "^16.2.0",
"@angular/core": "^16.2.0",
"@angular/forms": "^16.2.0",
"@angular/material": "^16.0.0",
"@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.2.0",
"@ngx-formly/core": "^6.1.8",
"@ngx-formly/material": "^6.2.2",
"ngx-mask": "^16.4.2",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.13.0"

Though I was able to reproduce with more up to date versions (see the StackBlitz).

@shyambhiogade
Copy link

try using
[(ngModel)]="startTime"

@LoginovSergey
Copy link

Any solutions?

@weilinzung
Copy link

same issue with NG_VALUE_ACCESSOR with normal reactive form

@kevindqc
Copy link

kevindqc commented Aug 13, 2024

I don't use formly, just angular material directly, but see the same issue. I think the problem is because the value is being set this way:

Promise.resolve().then(() =>

It's done in a Promise.then() (added for #803, change here), which means that the value is set after angular material has checked if it needs to float the label or not (https://github.com/angular/components/blob/bd84c2a67476b688a0c775de8566a4ff4b3b2ce0/src/material/form-field/form-field.html#L16)

So I think either the value needs to be written right away, or maybe it could call onChange so that Angular material knows there is a new value and do its markForCheck, which will re-check if the label needs to be floated or not (https://github.com/angular/components/blob/bd84c2a67476b688a0c775de8566a4ff4b3b2ce0/src/material/form-field/form-field.ts#L447)

@seeplusplus
Copy link

+1 on this, can repro with Angular, Material, and ngx-mask.

Steps to reproduce:

  1. Make a new Angular project without SSR (I can't explain why, but when the app has SSR this issue doesn't happen)
  2. Set the following in app.component.ts/app.component.html:
import { NgxMaskDirective } from 'ngx-mask';
import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  inject,
} from '@angular/core';
import {
  FormControl,
  FormGroup,
  FormsModule,
  ReactiveFormsModule,
} from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    MatFormFieldModule,
    FormsModule,
    NgxMaskDirective,
    MatInputModule,
    MatFormFieldModule,
    ReactiveFormsModule,
  ],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
  budget = new FormControl(1500);

  form = new FormGroup({
    budget: this.budget,
  });
  /* - fixes the bug 
private cdr = inject(ChangeDetectorRef);
  ngAfterViewInit() {
    setTimeout(() => this.cdr.markForCheck(), 0);
  }
*/
}
<form [formGroup]="form">
  <mat-form-field class="mb-24">
    <mat-label class="ui-text-md">Budget amount</mat-label>
    <input matInput  mask="separator.2" thousandSeparator="," numericOnly formControlName="budget" />
  </mat-form-field>
</form>

@krutkowski86
Copy link

+1 same issue with angular material form field component

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

No branches or pull requests

8 participants