0

Since my text and date inputs on an Angular form (built with *ngFor) have all the same styling (except for the type of input, of course), I want to combine them to make them easier to maintain. So I have done the following:

<div *ngFor="let form of source">
  <div [ngSwitch]="form.type">
    <mat-form-field *ngSwitchDefault>
      <mat-label>{{form.displayName}}</mat-label>
      <ng-container [ngSwitch]="form.format">
        <input *ngSwitchDefault matInput formControlName="{{form.displayName}}" otherAttributes
               [attr.matDatepicker]="form.type === 'date' ? 'picker' : null">
      </ng-container>
      <mat-datepicker-toggle *ngIf="form.type === 'date'" matSuffix [for]="picker"></mat-datepicker-toggle>
      <mat-datepicker #picker></mat-datepicker>
    </mat-form-field>
  </div>
</div>

I originally tried this without the attr. on the matDatepicker in the input, but then the compiler complains that Type 'string | null' is not assignable to type 'MatDatepickerPanel<MatDatepickerControl<any>, any, any>'. Using attribute binding is supposed to drop the attribute altogether when it evaluates to null or undefined, but when I do it this way, it compiles fine but the browser fails with Attempted to open an [sic] MatDatepicker with no associated input when I click the datepicker toggle, so it would seem it fails to set the attribute in either case. I get this result whether I have quotes around picker in the expression or not, since the rules for attribute binding specify that it should evaluate to a string.

Does this mean that attribute binding won't work for this situation? What else might I be doing wrong here? Is there some other trick I can use to base the text and date inputs on the same definition, or am I going to have to write and maintain almost identical definitions for these two controls?

Edit: Oh, and if I don't make it optional, then it forces all my non-date inputs to only take date inputs.

Trevortni
  • 688
  • 8
  • 23

1 Answers1

-1

Does this mean that attribute binding won't work for this situation?

I am sorry to say that, but: Yes, this won´t work.

That is because you apply a value to an attribute but you don´t actually create the directive. (Compare: Apply a directive conditionally)

So unfortunatly you can´t use a single input for what you want to achieve. At least you only need a single mat-form-field. (Small hint: The closing tag is missing)

christoph
  • 1,019
  • 1
  • 12
  • 23
  • Ah, the missing closing tag, the joys of copying code by hand never cease. I also forgot the closing `>` on the `input`; I've fixed both now. Unfortunately, other switch cases aren't compatible with `mat-form-field`, so I get the choice to either make yet another switch statement inside the `mat-form-field`, or multiple `mat-form-field`s. I choose the latter. – Trevortni Feb 08 '22 at 20:14
  • Well, making multiple `mat-form-field` makes no sense I think. Remove the `ngSwitch` from the div and move it to `mat-form-field`. Make standard text input your default and an `ng-container` (which includes another input + datepicker components) for date types. – christoph Feb 08 '22 at 20:19
  • Again, there are other switch cases not shown which are not compatible with `mat-form-field`. For example, radio buttons are not compatible with `mat-form-field`, so either I nested `switch` the same value twice, or I make multiple `mat-form-field`s. Of the two, nesting the same `switch` feels more "wrong" to me, but I suppose that's a personal preference, Either way, I duplicate some work somewhere. – Trevortni Feb 08 '22 at 21:17
  • As I look at it, I almost agree with you, but the switch statements start to look like spaghetti if I do it, which almost defeats the purpose of making it more readable and maintainable. My original idea would have simplified some of the mess, but I think it's at right at the point where doing it halfway is worse than not doing it at all, especially since I had already made the duplicate `mat-form-field` that I was hoping to simplify away. – Trevortni Feb 08 '22 at 21:26