0

Given a particular formGroup and it's corresponding HTML form

this.fieldForm = new FormGroup({
      fieldId: new FormControl(null),
      fieldName: new FormControl("", Validators.required),
      sourceCreateBy: new FormControl(null),
      sourceUpdateBy: new FormControl(null),
    }, {validators: FieldFormValidators.invalidFormInput})  // some other logic

Consider the scenario that fieldName = "WORKFORCE". In the HTML Form, I edit the input field to make the value first "WORKFORCE_1" and then back to "WORKFORCE". The formGroup attributes have changed from pristine=true, dirty=false, touched=false to pristine=false, dirty=true, touched=true.

Hence the form is valid. But actually no data change has taken place. Are there any inbuilt FormControl or FormGroup attributes or any combination thereof that can help me disable the "UPDATE" button or can I do such validation only after the fact(UPDATE button click)?

Can I create a custom validator to address this validation logic?

Ayush Nair
  • 43
  • 6
  • Check this: https://stackoverflow.com/questions/50405358/angular2-detect-if-data-in-an-angular-form-reactive-was-changed – robert Apr 06 '21 at 14:58
  • @robert I Checked it out. But again it only deals with the cosmetic changes like `dirty, pristine, touched`. The other answer is that deals with validation after the fact in `submitForm()`. Thank you for your reply. You can check out the marked answer below to see what kind of solution I was actually looking for. Thanks again. – Ayush Nair Apr 07 '21 at 07:23

1 Answers1

1

You can create a custom validator "isDifferent", but first reemplace the way to create the form using a function

getForm(data:any=null){
  data=data|| {fieldID:null,fieldName:"",sourceCreateBy:null,sourceUpdateBy:null}
  return FormGroup({
      fieldId: new FormControl(null),
      fieldName: new FormControl("", Validators.required),
      sourceCreateBy: new FormControl(null),
      sourceUpdateBy: new FormControl(null),
    }, {validators: [FieldFormValidators.invalidFormInput,isDifferent(data)]}) 
getForm(data:any=null){
  data=data|| {fieldID:null,fieldName:"",sourceCreateBy:null,sourceUpdateBy:null}
  return FormGroup({
      fieldId: new FormControl(data.fieldID),
      fieldName: new FormControl(data.fieldName, Validators.required),
      sourceCreateBy: new FormControl(data.sourceCreatedBy),
      sourceUpdateBy: new FormControl(data.sourceUpdateBy),
    }, {validators: [FieldFormValidators.invalidFormInput,isDifferent(data)]})  // some other logic

isDiferent(data:any){
   return (control:AbtractControl)=>{
     bool equal=true;
     Object.keys(data).forEach(key=>{
        equal=equal && data[key]==control.value[key]
     })
     return equal?{error:"must be different"}:null
   }
}

You use as

this.fieldForm=this.getForm(..your object...)

Update:Aclaration. Well the code above goes from I imagine a typical REST. So if we has a component to Edit/Create a register we has a router like

{ path: 'hero/:id',component: HeroDetailComponent },

Where, possible id values are a number or "new", so we can has

url=hero/new  //edit-component to create a new "hero"
url=hero/1    //edit-compoent to edit the hero with "id=1"

Our component, that has an form and use reactiveForm take account this, so

constructor(private activatedRoute: ActivatedRoute,private service: HeroService) {}
form:FormGroup
status:string //here we store if "new" or "edit" to use for e.g.
              //the button "submit" show a message "create" or "update"
ngOnInit() {
  this.activatedRoute.paramMap.pipe(
    switchMap(params => {
      const id=params.get('id')
      if (id=="new"){
          this.form=this.getForm();  //create a empty form
          this.status="new"
      }
      else{
         //use "+id" to convert to number the "id"
         this.service.getHeroe(+id).subscribe(res=>{
             //here we has the "data of the "hero"
             this.form=this.getForm(res)  //create a form with the data of hero
             this.status="edit"
         })
      }
  );
}

Our .html needn't a complex handlers in inputs, e.g. our button "submit" can be

<!--see that the button is disabled if the form is invalid
    if it's not invalid you need equal "disabled" to null,
    **not** to false
--->

<button disabled="form.invalid?true:null">
     {{status=="new"?"Create":"Update"}}
</button>
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • what data do I pass to `getForm()` function? Will I have to write custom event handlers on the inputs to call the `getForm()`? Because right now I only have to setup the `formControlName` directive in the HTML and then `fieldForm` is automatically updated. – Ayush Nair Apr 07 '21 at 06:12
  • @AyushNair, you're correct. The "code" goes from a more complex component. I added to the answer a little example in an imaginarium component to update/create a "hero". In the example you needn't write custom event handers – Eliseo Apr 07 '21 at 06:35
  • Your solution worked beautifully. Thank you so much. Only thing I changed was put the `isDifferent` method in a separate validator file. One more thing. From all those fields only fieldName is modifiable from HTML and the rest will be fixed programmatically using `patchValue()`. I can change the data object to be only `data = data || { fieldName: "" }`. This will make it more efficient I think. Shouldn't throw any issues right? – Ayush Nair Apr 07 '21 at 07:13
  • @AyushNair, Sorry ::glups::, there are a mistake in my code, see the updated getForm function. So you understand that you need create on fly an object with all the properties – Eliseo Apr 07 '21 at 07:24