0
votes

I have a formControl with value set to object like {id: 1, name: 'Ramesh'}. The input field inside mat-form-field is read-only and value either coming from database or selected from a pick list.

To show different view value I am using [value] binding like below. Its correctly displaying when control is updated later by the user. But when its initialized for the first time with saved value its showing [object Object].

Internally its depending upon the order of execution of DefaultValueAccessor writeValue method and [value] binding.

https://stackblitz.com/edit/angular-ivy-mkvx8a?file=src%2Fapp%2Fapp.component.ts

<input readonly [formControl]="userControl" [value]="userControl.value?.name">

I thought to create custom value accessor but it seems too much.

1
If it's readonly input then you dont need to bind formControl directive, simply using value attribute is enough - Chellappan வ
@Chellappanவ I have validation as well driven by formControl and for consistent styling its inside mat-form-field along with other fields. - Amitesh
if you remove formControl directive from template does it effect your form validation and style? - Chellappan வ
yes. By removing formControl, fields doesn't get highlighted as red(default style in mat-form-field). No error class added to the container. - Amitesh

1 Answers

1
votes

I have solved it by extending DefaultValueAccessor and providing custom writeValue method. But I feel angular should provide a way for just custom writeValue method.

For example mat autocomplete has displayWith

Demo: https://stackblitz.com/edit/angular-ivy-mkvx8a?file=src%2Fapp%2Fapp.component.html

<input valueKeyAccessor [formControl]="control">
@Directive({
  selector: "input[valueKeyAccessor]",
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => valueKeyAccessor),
      multi: true
    }
  ]
})
export class valueKeyAccessor extends DefaultValueAccessor {
  @Input("valueKeyAccessor") propToDisplay;

  writeValue: any;
  constructor(
    _renderer: Renderer2,
    _elementRef: ElementRef,
    @Optional() @Inject(COMPOSITION_BUFFER_MODE) _compositionMode: boolean
  ) {
    // Refer signature from https://github.com/angular/angular/blob/9.1.11/packages/forms/src/directives/default_value_accessor.ts#L36-L156
    super(_renderer, _elementRef, _compositionMode);
    // overwriting the writeValue    
    this.writeValue = value => {
      value = value && value[this.propToDisplay];
      const normalizedValue =
        (value === undefined || value === null) ? "" : value;
      super.writeValue(normalizedValue);
    };
  }

  ngOnInit() {
    this.propToDisplay = this.propToDisplay || "name";
  }
}