0

my form input field required or not decide according to the API data set. But when it mandatory, I need to disable button, until user input some value. I am an absolute beginner for reactive form in angular. need some expert help to do this.

------------HTML----------------------

 <div class="a">
      <at-card *ngIf="selectedId$|async" class="b">
        <at-detail [selectedDetail]="selectedDetailModel$|async">
        </at-detail>
        <div [formGroup]="DetailForm" class="grid grid-columns-2">
          <br />
          <mat-form-field>
            <mat-label>Comment</mat-label>
            <input matInput formControlName="comment" [type]="'text'" [required]="commentRequerd">
          </mat-form-field>
        </div>
      </at-card>
      <at-sticky-footer>
        <button *ngIf="selectedId$|async" (click)="onSubmit()">submit</button>
      </at-sticky-footer> 
</div>

------------------component.ts------------------

commentRequerd: boolean;

DetailForm = new FormGroup({ comment: new FormControl(), rate: new FormControl() });

ngOnInit(): void {
   inputCommentIsMandotory:boolean = <take API data about enter comment needed or not>
         
   //accroding to that input comment filed mark as requred->
   //is it requred need to check user input data to comment field -> 
   //if it avalable button is enable , else it disable
   if(inputCommentIsMandotory){
    this.commentRequerd = true;
    //when user enter data button enable , if not disable(input field empty)
    }else{
    //alwasy button enable (input comment or not)
    this.commentRequerd = false;
    }
 
  }

------------------latest update (button always disable , even if a comment is not mandatory ------------------------------------

I changed the code like bellow.

isCommentMandatory(Reviews: ReviewModel[]): void {
  

      if (Reviews.length > 0) {
          console.log("called ...1 ");
          this.isCommentRequired = false;
          this.DetailForm = this.fb.group({
            comment: [''],
            rate: ['']
          });
        } else {
          console.log("called ...2 ");
          this.isCommentRequired = true;
          this.DetailForm = this.fb.group({
            comment: ['', Validators.required],
            rate: ['']
          });
        }
      }

and called it like this,

ngOnInit(): void {
  
       this.DetailModel$.pipe().subscribe((opd => {
          this.detail = opd as Detail;
          const date = this.detail?.time;
          const planDate = date !== undefined ? date : new Date();
          //according date select reviews data
          this.store.select(selectAllReviewsDetailsModel(planDate)).
            subscribe(res => this.Reviews = res);
    
          //need to call after change Details
          this.isCommentMandatory(this.Reviews);
        }));
      }

In the html template it bind has below,

 <at-sticky-footer>
        <button *ngIf="selectedId$|async" [disabled]="!(DetailModel.valid && (DetailModel.dirty))" (click)="submit()">submit</button>
      </at-sticky-footer>

but now , both situation need to type something to enable button .

uma
  • 1,477
  • 3
  • 32
  • 63
  • 1
    Does this answer your question? [Disable Button in Angular 2](https://stackoverflow.com/questions/43978380/disable-button-in-angular-2) – R. Richards Aug 28 '20 at 14:18

1 Answers1

2

The idea around reactive forms is the unidirectional data flow. Data flows from the component to the template; when the user is done with the data, they click "save", and the component takes over again.

If data validation is needed, it's done in the component, if there is conditional logic that changes the data, it's in the component. If there's behavioral (but no data or validation change), then it's OK for it to be a template directive. (as a 'for instance', popping up a "this row changed" visual indicator as a highlight is perfectly fine in the template as a directive).

All those controls in your form are Observables; that means you can watch for them to change in the component and 'do the right thing', but your usecase is simple enough that when you're setting up the form you can do the right thing. As a note, you may want to hold off on your form building until the Http.GET returns; as that is an asynchronous event; that would mean putting your formbuilding logic inside of the closure for the http call.

Save Button

For the save button, you can use:

<button [disabled]="!(DetailForm.touched && DetailForm.valid)">

since DetailForm is the variable name for your base FormGroup is.

The comment form control needs a [Validator.Required] in its definition:

 this.DetailForm= this.fb.group({
      comment: ['', Validators.required]
  });

It's also important to note you can create a Custom Validation when you're creating the form and getting the data from the server initially to see if that comment should be required.

How to structure the form group and form builder:

Thanks for your update; based on that, here is how I'd structure the component.ts:

constructor(private fb: FormBuilder) { }
DetailForm: FormGroup;


ngOnInit(): void {
   const dataAvailable = //this.http.get<boolean>(s =>  s);
   if (dataAvailable) { 
     this.DetailForm = this.fb.group({ 
      comment: ['', Validators.Required]
     });
   }
   else { 
     this.DetailForm = this.fb.group({ 
      comment: [''];
     })
   }
  }
   

component.html

<div class="a">
      <at-card *ngIf="selectedId$|async" class="b">
        <at-detail [selectedDetail]="selectedDetailModel$|async">
        </at-detail>
        <div [formGroup]="DetailForm" class="grid grid-columns-2">
          <br />
          <mat-form-field>
            <mat-label>Comment</mat-label>
            <input matInput formControlName="comment" [type]="'text'">
          </mat-form-field>
        </div>
      </at-card>
      <at-sticky-footer>
        <button [disabled]="!(DetailForm.valid && (DetailForm.touched ||  DetailForm.dirty)"  (click)="onSubmit()">submit</button>
      </at-sticky-footer> 
</div>

Note on touched and blurred:

touched: means the control has been activated, changed, and blurred; dirty: means the control has been activated, changed, but not yet blurred.

The one you need to use depends on your usecase.

George Stocker
  • 57,289
  • 29
  • 176
  • 237
  • am , I need to create 'constructor(private fb: FormBuilder) {} ' ? (i added it my .ts constructer and wrote that validators.req... think inside , ngInt .is it ok ? – uma Aug 28 '20 at 14:42
  • @Georage as i understood , it is no need 'this.commentRequerd = true;' like this thing and apart from that, it is ok to dirrecly add validation there ?(remove 'commentRequerd ' in input filed flag also) – uma Aug 28 '20 at 15:04
  • i added some code comments what ,i am needed to done, i try your solution but then always button disable – uma Aug 28 '20 at 15:58
  • @Geroge I used dirty. :) I did little dev test , it working as expected. Thanks lot. – uma Aug 28 '20 at 17:10
  • @Geroge I implemented with new test data.. but now , the button is disable both situation :( I cannot, have an idea why. it enables only I put some thing in comment field – uma Sep 01 '20 at 11:47
  • can you help me, plz. https://stackoverflow.com/questions/63688564/initaly-input-feild-not-mandotory-but-still-submit-button-disable/63688740?noredirect=1#comment112624533_63688740 – uma Sep 01 '20 at 15:03