Search code examples
angular-flex-layoutangular-material-7

how to use angular material form field and flex-layout


I want to have 2 form input fields in one row: 1. the first has a fixed with, 1. the second should grow and shrink, but this does not shrink below 180px.

Here is a full stack-blitz example

When you start the app, we see this
enter image description here

There maybe another issue:
I think the 2nd input field should already show the hint text and the horizontal line - but it will only show it when it get's the focus.
Is this the expected behaviour or am I missing something?

Anyway. The main issue is that the 2nd field does not shrink as expected. It will not shrink below 180px:
enter image description here

In the chrome dev-tool I can see that the input element is wrapped with a div class="mat-form-field-infix"> and the class mat-form-field-infix has a fixed width of 180px!

The only workaround that I came up with is to override this width with using ::ng-deep.
You can activate this in the co-input-field.component.scss file of the Stackblitz example

:host ::ng-deep .mat-form-field-infix {
  // width: auto !important;
  width: unset !important;
}

With this workaround the 2nd input shrinks as expected:
enter image description here

But ::ng-deep is deprecated and will be removed.
So what is the right way to make the input shrink as expected?


Solution

  • since .mat-form-field-infix has a fixed width of 180px there is no way of making form field shrink beyond 180px. inevitably .mat-form-field-infix must be overridden.

    you can achive the same result with ::ng-deep in a couple of ways;

    1.disable view encapsulation for that particular component. However, this approach has a huge drawback that all the styles in your component becomes global so they need to be managed carefully.

    @Component({
        selector: 'app-co-input-field',
        templateUrl: './co-input-field.component.html',
        styleUrls: ['./co-input-field.component.scss'],
        encapsulation: ViewEncapsulation.None
    })
    export class CoInputFieldComponent {}
    

    and then in co-input-field.component.scss you do the following

    app-co-input-field {
        .mat-form-field-infix {
          width: auto !important;
        }
        // all other component styles goes in here
        // in order to keep them isolated from global scope
    }
    

    2.don't disable view encapsulation. use the element selector of parent component in global styles.

    put the following in styles.scss

    app-co-input-field {
        .mat-form-field-infix {
          width: auto !important;
        }
        // co-input-field.component.scss still can be used for encapsulated styles
    }
    

    3.don't disable view encapsulation. define a global rule for this particular situation.

    put the following in styles.scss

    .shrinking-mat-form-field {
        .mat-form-field-infix {
          width: auto !important;
        }
    }
    

    and apply the .shrinking-mat-form-field class to corresponding element

    <mat-form-field style="width: 100%" class="shrinking-mat-form-field">
      <input matInput placeholder="placeholder"  />
      <mat-hint align="end">hint text</mat-hint>
    </mat-form-field>
    

    Even though second and third approaches are fundamentally same I personally prefer the third approach in order to make it readable, keep it consistent over the project, have minimal side effects and manage them from a single point.