Amitesh
Amitesh

Reputation: 1517

Simple solution for different model and view value in Reactive input control in Angular

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.

Upvotes: 0

Views: 2020

Answers (1)

Amitesh
Amitesh

Reputation: 1517

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";
  }
}

Upvotes: 1

Related Questions