1

I have a custom form control which implements ControlValueAccessor to handle [(formControl)]="..." and [(ngModel)]="...".

@Component({
  selector: 'app-foo',
  templateUrl: './foo.component.html',
  styleUrls: ['./foo.component.css'],
    providers: [
        {
            provide: NG_VALUE_ACCESSOR,
            useExisting: forwardRef(() => FooComponent),
            multi: true,
        },
    ],
})
export class FooComponent implements ControlValueAccessor, OnInit, AfterContentInit, OnInit, OnChanges, DoCheck, AfterContentChecked, AfterViewInit, AfterViewChecked {

  constructor() { }

  ngOnChanges() {
    console.log('ngOnChanges', this.value);
  }
  ngOnInit() {
    console.log('ngOnInit', this.value);
  }
  ngDoCheck() {
    console.log('ngDoCheck', this.value);
  }
  ngAfterContentInit() : void {
    console.log('ngAfterContentInit', this.value);
  }
  ngAfterContentChecked() : void {
    console.log('ngAfterContentChecked', this.value);
  }
  ngAfterViewInit() : void {
    console.log('ngAfterViewInit', this.value);
  }
  ngAfterViewChecked() : void {
    console.log('ngAfterViewChecked', this.value);
  }

  /**
   * Write a new value to the element.
   */
  public writeValue(value : any) : void { // tslint:disable-line:no-any
    this._value = value;
    console.log('writeValue', this.value);
  }

  ...

I use this component like this:

<app-foo [ngModel]="true"></app-foo>

I assumed the value should be defined at least in ngAfterContentInit() but it is always undefined or null. At least in the first run. Here are my console logs:

ngOnInit undefined
ngDoCheck undefined
writeValue null
ngAfterContentInit null
ngAfterContentChecked null
ngAfterViewInit null
ngAfterViewChecked null
---
writeValue true
ngDoCheck true
ngAfterContentChecked true
ngAfterViewChecked true

Why is value always undefined/null and is there a way to change that?

DerZyklop
  • 3,672
  • 2
  • 19
  • 27
  • 1
    it's not ``? – Eliseo Sep 13 '19 at 07:20
  • @Eliseo `[ngModel]` is one-way-binding `[(ngModel)]` is two-way-binding. Changing this has no effect to my described issue. – DerZyklop Sep 13 '19 at 12:24
  • I think you should give a default value of empty quotes. So it would be null not Undefined. – Silambarasan R Sep 13 '19 at 12:41
  • why cant you declare 'value' variable at class level and set default value there itself. because writeValue() call only in specific circumstance. Read from official site: 'This method is called by the forms API to write to the view when programmatic changes from model to view are requested.' – Harshad Vekariya Sep 13 '19 at 12:47

1 Answers1

1

You will need to implement ControlValueAccessor in order to make it work :

export class FooComponent implements ControlValueAccessor {
  writeValue(value) {
   this._value = value;
  }
  ...
}

The writeValue function will be executed when the input value of ngModel change. You will also have to implement registerOnTouch and registerOnChange.

Have a look at this alligator.io article for a more information.

ibenjelloun
  • 7,425
  • 2
  • 29
  • 53
  • You are right, but it does not solve the described issue, that value is undefined in ngOnAfterContentInit. I think ngOnAfterContentInit should run after all properties of reach the FooComponent. – DerZyklop Sep 13 '19 at 12:02
  • I added ControlValueAccessor to the Example and tried `console.log('writeValue', this.value);` in writeValue(), but in the first run, this.value is null here. – DerZyklop Sep 13 '19 at 12:20
  • 1
    In your code you're initializing `this._value` and trying to console.log `this.value` – ibenjelloun Sep 13 '19 at 13:35