Angular2 manually implement change detection using ApplicationRef
Asked Answered
A

2

9

Getting a change detection error

Expression has changed after it was checked. Previous value: 'true'. Current value: 'false'

so I want to manually run another round of change detection. Found information about using ApplicationRef.tick() but currently getting error

ERROR in [default] C:\development\SolarUI11\src\app\update\update.component.ts:8 :11 Argument of type '{ selector: string; styles: any[]; template: any; providers: ( typeof ApplicationRef | typeof Date...' is not assignable to parameter of type ' Component'. Types of property 'providers' are incompatible. Type '(typeof ApplicationRef | typeof DatePipe)[]' is not assignable to type 'Provider[]'. Type 'typeof ApplicationRef | typeof DatePipe' is not assignable to type ' Provider'. Type 'typeof ApplicationRef' is not assignable to type 'Provider'. Type 'typeof ApplicationRef' is not assignable to type 'FactoryProvide r'. Property 'provide' is missing in type 'typeof ApplicationRef'.`

I think I'm just stuck on the syntax of implementing this, couldn't find enough information myself to be able to use it.

Typescript:

import { Component, Input, ApplicationRef } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import {NgbDateStruct} from '@ng-bootstrap/ng-bootstrap';
import {DatePipe} from "@angular/common";
import { DataTable } from '../data/datatable';
import { DPS } from '../data/datainfo.ts';

@Component({
  selector: 'update-validation',
  styleUrls: ['../app.component.css'],
  templateUrl: 'update.component.html',
  providers: [DatePipe, ApplicationRef]
})
export class UpdateComponent {
  @Input() receivedRow:DataTable;
   public dt: NgbDateStruct;
   public dt2: NgbDateStruct;
   public startCheck: boolean = false;
   public endCheck: boolean = false;
   updateForm : FormGroup;

   constructor(fb: FormBuilder, private datePipe: DatePipe, private appref: ApplicationRef){
     this.updateForm = fb.group({
      'dataPoint' : [null, Validators.required],
      'ICCP' : [null, Validators.required],
      'startDate' : [null, Validators.required],
      'endDate' : [null, Validators.required]
      }, {validator: this.endDateAfterOrEqualValidator})
   }

 ngOnChanges(){
if(this.receivedRow){
  this.updateForm.controls['dataPoint'].setValue(this.receivedRow.tDataPoint);
  this.updateForm.controls['ICCP'].setValue(this.receivedRow.tICCP);
  this.updateForm.controls['startDate'].setValue(this.receivedRow.tStartDate);
  this.updateForm.controls['endDate'].setValue(this.receivedRow.tEndDate);
  }
}

  resetForm(){
    location.reload();
    //this.updateForm.reset();
  }

  submitForm(value: any, originalRow: any){
    var dataPointID = originalRow.receivedRow.tDataPoint;
    for (let entry in DPS) {
      if (DPS[entry].tDataPoint === dataPointID) {
        DPS[entry].tDataPoint = String((<HTMLInputElement>document.getElementById("dataPoint")).value);
        DPS[entry].tICCP = String((<HTMLInputElement>document.getElementById("ICCP")).value);
        DPS[entry].tStartDate = String((<HTMLInputElement>document.getElementById("startDate")).value);
        DPS[entry].tEndDate = String((<HTMLInputElement>document.getElementById("endDate")).value);
      }
    }
  }

  getStartDate(){
    var month = this.receivedRow.tStartDate.substring(0,2);
    var day = this.receivedRow.tStartDate.substring(3,5);
    var year = this.receivedRow.tStartDate.substring(6,10);
    var dateToUse = new Date(Number(year),Number(month)-1,Number(day));
    let timestamp = this['startDate'] != null ? new Date(this['startDate'].year, this['startDate'].month-1, this['startDate'].day).getTime() : dateToUse.getTime();
    this.updateForm.controls['startDate'].setValue(this.datePipe.transform(timestamp, 'MM/dd/yyyy'));
    this.appref.tick();
  }

  getEndDate(){
    var month = this.receivedRow.tEndDate.substring(0,2);
    var day = this.receivedRow.tEndDate.substring(3,5);
    var year = this.receivedRow.tEndDate.substring(6,10);
    var dateToUse = new Date(Number(year),Number(month)-1,Number(day));
    let timestamp = this['endDate'] != null ? new Date(this['endDate'].year, this['endDate'].month-1, this['endDate'].day).getTime() : dateToUse.getTime();
    this.updateForm.controls['endDate'].setValue(this.datePipe.transform(timestamp, 'MM/dd/yyyy'));
    this.appref.tick();
  }

  public showDatePick(selector):void {
     if(selector === 0) {
       this.startCheck = !this.startCheck
     } else {
       this.endCheck = !this.endCheck;
     }
  }

  endDateAfterOrEqualValidator(formGroup): any {
    var startDateTimestamp, endDateTimestamp;
    for(var controlName in formGroup.controls) {
      if (controlName.indexOf("startDate") !== -1) {
       startDateTimestamp = Date.parse(formGroup.controls[controlName].value);
      }
      if (controlName.indexOf("endDate") !== -1) {
        endDateTimestamp = Date.parse(formGroup.controls[controlName].value);
      }
    }
    return (endDateTimestamp < startDateTimestamp) ? { endDateLessThanStartDate: true } : null;
  }
}
Adler answered 18/11, 2016 at 17:2 Comment(0)
J
15
import { Component, Input, ChangeDetectorRef } from '@angular/core';

Inject

constructor(private cdRef:ChangeDetectorRef) {}

and use it

public showDatePick(selector):void {
  if(selector === 0) {
    this.startCheck = !this.startCheck
  } else {
    this.endCheck = !this.endCheck;
  }
  this.cdRef.detectChanges();
}
Just answered 18/11, 2016 at 17:16 Comment(4)
that actually fixed the second error, not the first. Do I simply insert private cdRef:ChangeDetectorRef into my already existing instructor or is there some sort of inject syntax I include?Adler
Perhaps you need to add this.cdRef.detectChanges() at other places as well. Your question contains too much code. I didn't fully investigate.Enhance
You haven't explained why we are not using ApplicationRef. Is that obsolete now?Knowhow
ApplicationRef.tick() is somehow similar but runs change detection for the whole application. If this is not necessary, it's better to avoid it. If a component has ChangeDetectionStrategy.OnPush configured, ApplicationRef.tick() would still skip this component for change detection and therefore wouldn't solve the problem.Enhance
B
3

Have you tried using ChangeDetectorRef?

constructor(private changeDetector: ChangeDetectorRef) {
}

And detect the changes with

changeDetector.detectChanges();
Brought answered 18/11, 2016 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.