0

So I have a function that displays a list from an API:

displayEventTicketDetails() {
  this.Service
      .getEventTicketDetails().subscribe((data: any) => {
        this.eventTicketDetails = data.map(ticket => ticket.ticket_name);
        console.log(this.eventTicketDetails);
      });
  }

This is the result from the function above: ["Regular", "VIP", "Table", "Testing", "Cabana"]

Here is how the form array is declared:

ngOnInit() {
    this.composeMessage = this.fb.group({
      ticket: new FormArray([])
    });

Then I use this function below to track if the check boxes are checked

  onChange(event: any, isChecked: boolean){
      const control = <FormArray>this.composeMessage.controls.ticket;
      if(isChecked){
        control.push(new FormControl(event))
      } else{
        const index = control.controls.findIndex(x => x.value === event);
        control.removeAt(index)
      }
  }

Then finally in my ts file, here is my onsubmit function that submits the data on the form:

 submitComposeMessage() {
    this.submitted = true;
    if (this.composeMessage.invalid) {
      return;
    } 
    const ticket = this.f.ticket.value;
    this.Service
      .createMessage(
        ticket)
      .subscribe(
        (res: any) => {
          if (res.err) {
            this.toaster.errorToastr(res.message, null, { toastTimeout: 5000 });
            return false;
          }
          this.toaster.successToastr(res.message, null, { toastTimeout: 5000 });
          console.log("Message successfully created");
        },
        err => {
          console.log(err);
        }
      );
  }

So in my Html file here is my input field:

 <ng-container *ngFor="let event of eventTicketDetails; let i = index"  >
  <label class="w-checkbox checkbox-field" >
    <input 
    type="checkbox" 
    id="{{i}}"
    name="checkbox-9"
    class="w-checkbox-input checkbox"
    (change)="onChange(event, $event.target.checked)"
    [checked]="composeMessage.controls.ticket.value.indexOf(event)>=0">
      <span class="no-margin w-form-label">{{event}}</span>
  </label>
</ng-container>

With that loop, I'm able to get this result enter image description here

So, I need help with two things:

1). I want all the checkbox to be checked by default when the page loads at first instance. 2). I want to validate the checkbox to ensure at least one checkbox is checked on submission.

I'll appreciate any help I can get.

2 Answers 2

1

If you want to only show validation message after submit, I would suggest the following, where we instead iterate the formarray in template, initially set all checked (as that is what you wish). We would listen to valueChanges of the formarray, but filter out as long as form is not submitted. We would introduce a new variable, for example isEmpty, which based on we would show/hide validation message. So all in all....

TS:

isEmpty = false;
submitted = false;

constructor(private fb: FormBuilder) {
  const ctrls = this.eventTicketDetails.map(control => this.fb.control(true));
  this.composeMessage = this.fb.group({
    ticket: this.fb.array(ctrls)
  });

  this.tickets.valueChanges.pipe(
    filter(() => !!this.submitted)
  ).subscribe((value) => {
    value.some(x => x === true) ? this.isEmpty = false : this.isEmpty = true;
  })
}

get tickets() {
  return this.composeMessage.get("ticket") as FormArray;
}

onSubmit() {
  this.submitted = true;
  const selectedTickets = this.tickets.value
    .map((checked, i) => (checked ? this.eventTicketDetails[i] : null))
    .filter(value => !!value);
  selectedTickets.length ? this.isEmpty = false : this.isEmpty = true
}

HTML:

<label formArrayName="ticket" *ngFor="let t of tickets.controls; index as i">
  <input type="checkbox" [formControlName]="i">
  {{eventTicketDetails[i]}}
</label>
<small *ngIf="isEmpty">Choose at least one checkbox</small>

STACKBLITZ

Sign up to request clarification or add additional context in comments.

3 Comments

This actually works if the values are staticlike this: eventTicketDetails = ["Regular", "VIP", "Table", "Testing", "Cabana"]; But the problem comes when I try passing the values from the data coming from my API in this function ``` displayEventTicketDetails() { this.Service .getEventTicketDetails().subscribe((data: any) => { this.eventTicketDetails = data.map(ticket => ticket.ticket_name); console.log(this.eventTicketDetails); }); }``` I get an error that says Cannot read property 'map' of undefined
well you need set the formcontrols in the callback (subscribe). The above was just a sample with static data.
Okay. I'll try that now.
1

change Id to something like this

id="ticket{{i}}"

In this method write like this and call displayEventTicketDetails on ngOnit. This will check all the values:

     displayEventTicketDetails() {
      this.Service
          .getEventTicketDetails().subscribe((data: any) => {
  this.eventTicketDetails = data.map(ticket =>ticket.ticket_name);
        setTimeout(() => {
             for(var i= 0;i < this.evenTicketDetails.length ; i++){  
              var id = "ticket" + i;
            (<HTMLInputElement>document.getElementById(id)).checked = true;   
                console.log(this.eventTicketDetails);
           }, 500);

          });
      }



  2. In submit method write something like this
    submitComposeMessage() {
                for(var i= 0;i < this.evenTicketDetails.length ; i++){  
                 var id = "ticket" + i;
                var resval =  (<HTMLInputElement>document.getElementById(id)).value;   
                   if(resval){

 // this will check atleast one value is checked and if it true we are coming 
                    out of the loop and performing other operations..
                i = this.evenTicketDetails.length;

               } 
               else{
                // show error message or block from going forward..
                }

             });

          }

This will solve your issues.

4 Comments

For some weird reasons, I got this error Cannot set property 'checked' of null
How are you assigning id’s in the HTML?
This way id="ticket{{i}}"
okay I got it I updated the answer. Please add setimeout function to your code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.