Chrillewoodz
Chrillewoodz

Reputation: 28368

Angular - Unable to set default value from inside a component when using ControlValueAccessor

Demo: https://plnkr.co/edit/cMu3lI3PkxHRErJE3T93?p=preview

I've got a few components which all seem to have the same problem, and that is that I can't set a default value for ngModel or formControlName when using ControlValueAccessor.

For example in the demo we have a select which provides better UX and visuals but in the ngOnInit I can't set the model to be the first item in the provided options if the select has a required input set to true.

If true, the select will always have a value. However now it only works after you actually clicked on an option.

One "solution" would be to always set the value in the parent of where it is being used. But that would require a lot of unnecessary code and I don't want to have to do that. Especially since setting a default value shouldn't be a problem.

So here's a short snippet of what we're working with:

  private _model: any;

  set model(val) {
    this._model = val;
  }

  get model() {
    return this._model;
  }

  propagateChange = (_: any) => {};

  registerOnChange(fn: () => any) {
    this.propagateChange = fn;
  }

  registerOnTouched() {}

  writeValue(value: any) {

    if (value !== undefined) {
      this.model = value;
      this.cd.markForCheck();
    }
  }

  ngOnInit() {

    if (!this.model && this.required) {
      this.model = this.options[0];
    }
    else if (!this.required) {
      this.model = null;
    }

    this.propagateChange(this.model);
  }

As you can see in the demo, the setting of the model in ngOnInit isn't working.

Why is this?

Upvotes: 2

Views: 1355

Answers (1)

yurzui
yurzui

Reputation: 214295

When you call this.propagateChange(this.model); this function has not registered yet.

So i know two workarounds

1) Update model after propagateChange was assigned

export const NOOP: any = () => {};
...

propagateChange = NOOP;

registerOnChange(fn: () => any) {
  this.propagateChange = fn;
  if(this.required) {
    fn(this.model);
  }
}

writeValue(value: any) {
  if (value !== undefined && this.propagateChange !== NOOP) {
    this.model = value;
    this.cd.markForCheck();
  }
}

Plunker Example

2) Use ngModelChange event

@Output() ngModelChange = new EventEmitter();

this.ngModelChange.emit(this.model);

Plunker Example

Upvotes: 3

Related Questions