Ryn9011
Ryn9011

Reputation: 179

Angular reactive form valueChanges function to detect and store only changed fields

Upon submitting the form, I want to capture only the values of the fields that have been changed.

Using the valueChanges function on the form captures every field of the form and it can't be traversed as an array as I've tried to do in my code below.

I'm not sure of any other way the 'before and after' values of a form can be compared and stored where only the fields that were changed are stored.

export class JobEditComponent implements OnInit {
jobNumber: any;
jobs: any[];
jobToEdit: Job;
job: any;
brands: Brand[];
jobForm: FormGroup;
bsConfig: Partial<BsDatepickerConfig>;
isFormReady: any;
jobId: number;
existingValues: string[] = [];
changedValues: string[] = [];


constructor(private route: ActivatedRoute,
  private jobService: JobService,
  private fb: FormBuilder,
  private router: Router,
  private alertify: AlertifyService) { }

ngOnInit() {
  this.route.params.subscribe(params => {
    this.jobNumber = +params['id'];
    });

    this.jobService.getJobToEdit().subscribe((jobs: Job[]) => {
      this.jobs = jobs;
    }, error => { console.log('error');
    }, () => {
      this.jobToEdit = this.jobs.find(j => j.id === this.jobNumber);
      this.editJobForm();
      this.onChanges();
    });

    this.getBrands();

    this.bsConfig = {
      containerClass: 'theme-blue'
    };
  }

onChanges(): void {
  this.jobForm.valueChanges.subscribe(val => {
    if (this.existingValues != null) {
      this.existingValues = val;
    }
  });
}


editJobForm() {
  this.jobForm = this.fb.group({
    jobNumber: [this.jobToEdit.jobNumber, Validators.required],
    item: [this.jobToEdit.item, Validators.required],
    status: [this.jobToEdit.status, Validators.required],
    orderedBy: [this.jobToEdit.orderedBy, Validators.required],
    orderDate: [this.jobToEdit.orderDate, Validators.required],
    quantity: [this.jobToEdit.quantity, Validators.required],
    unitPrice: [this.jobToEdit.unitPrice, Validators.required],
    lineValue: [this.jobToEdit.lineValue, Validators.required],
    dpAp: [this.jobToEdit.dpAp, Validators.required],
    eta: [this.jobToEdit.eta, Validators.required],
    detailStatus: [this.jobToEdit.detailStatus, Validators.required],
    comments: [this.jobToEdit.comments, null]
  }, ); this.isFormReady = true;
}

updateJob() {
  this.alertify.confirm('Are you sure you want save changes?', () => {
  this.jobId = this.jobToEdit.id;
  this.jobToEdit = Object.assign({}, this.jobForm.value);
  this.jobService.editJob(this.jobToEdit, this.jobId).subscribe(() => {
    this.alertify.success('Update successful');
    **for (let i = 0; i < this.existingValues.length; i++) {
      if (this.jobToEdit[i] !== this.existingValues[i]) {
         this.changedValues[i] = this.jobToEdit[i];
      }
    }**
    console.log(this.changedValues);
  }, error => {
    this.alertify.error(error);
  }, () => {
    this.router.navigate(['/home']);
  });
});
}

}

Upvotes: 2

Views: 3329

Answers (2)

Andriy
Andriy

Reputation: 15442

Try this for your loop:

// declare changedValues as key -> val object (not array)
changedValues: { [key: string]: any } = {};

Object.keys(this.existingValues).forEach(i => {
  if (this.jobToEdit[i] !== this.existingValues[i]) {
     this.changedValues[i] = this.jobToEdit[i];
  }
}

UPDATE

the same loop using for (key in object) syntax as proposed by @Alex:

for (let key in this.existingValues) {
  if (this.jobToEdit[key] !== this.existingValues[key]) {
     this.changedValues[key] = this.jobToEdit[key];
  }
}

Upvotes: 1

AVJT82
AVJT82

Reputation: 73357

You can check the values on submit, instead of using valueChanges, so if your form would look like this:

constructor(private fb: FormBuilder) {
  this.myForm = this.fb.group({
    field1: [this.values.field1],
    field2: [this.values.field2],
    field3: [this.values.field3]
  })
}

you can on submit check the values of the properties and see if they match:

// 'values' is 'myForm.values'
onSubmit(values) {
  let changed = {};
  for (let ctrl in values) {
    if(values[ctrl] !== this.values[ctrl]) {
      changed[ctrl] = values[ctrl];
    }
  }
  console.log(changed);
}

Here's a

StackBlitz

Upvotes: 0

Related Questions