How do I prevent an ion-checkbox from being checked?

I have an ion-checkbox that needs to only be checkable if a condition is met. If the condition is not met, I try to prevent the checkbox from being checked by calling event.preventDefault() on its (click) event, but that doesn’t work. The ion-checkbox still checks even though event.preventDefault() was called.
I then tried calling event.stopPropagation() on its (ionChange) event, however, I get an error saying event.stopPropagation is not a function.

<ion-checkbox [(ngModel)]="foo" (click)="checkFoo($event)"></ion-checkbox>
<ion-checkbox [(ngModel)]="bar" (ionChange)="checkBar($event)"></ion-checkbox>
foo: boolean = false;
bar: boolean = false;

checkFoo(event: any) {
  if (!condition) event.preventDefault();  // doesn't work, still checks
}
checkBar(event: any) {
  if (!condition) event.stopPropagation(); // throws error
}

How can I prevent the checkbox from being checked if my condition is not met?

Related to: https://github.com/ionic-team/ionic/issues/10309

1 Like

Take a look at the convo starting here.

1 Like

I can’t get the solution in the link you provided to work. Would it be because my condition is being determined inside an Observable’s subscription?
The below code checks the box on the first click, and unchecks the box and shows the modal on the second click. It should either check the box or keep the checkbox unchecked and show the modal.

<ion-checkbox [checked]="foo" (ionChange)="checkFoo($event)"></ion-checkbox>
foo: boolean = false; // default state of checkbox
fooSub: Observable<Foo>;

checkFoo(event: any) {
  this.fooSub.take(1).subscribe(foo => {
    if (foo && foo.id) {
      // check checkbox if foo has email, prevent check and show email modal if not
      if (event.checked !== (foo.email && foo.email.length)) {
        if (event.checked) {
          this.foo = true;
        } else {
          this.foo = false;
          this.showEmailModal();
        }
      }
    }
  });
}

Is the update happening but not being displayed? Then yes. You’re outside Angular change detection for two reasons: (1) Angular does not listen to ionChange, and (2) the inside of your subscribe is not in the Angular zone.

If the update isn’t happening at all, the subscription probably doesn’t matter, and the logic issue is elsewhere.

A naming note: I would call your Observable fooStream (or foo$ etc.), instead of fooSub. Use that for a Subscription, so fooSub.unsubscribe() can be called when you tear down the page.

You were right, it was a logic issue that I fixed.

checkFoo(event: Checkbox) { // import Checkbox from 'ionic-angular'
  if (event.checked != this.chkFoo) {
    if (event.checked) {
      this.foo$.take(1).subscribe(foo => {
        if (foo) {
          if (foo.email && foo.email.length) {
            this.chkFoo = true;
            return;
          }
          event.checked = false;
          this.showEmailModal();
        }
      });
    }
    else this.chkFoo = false;
  }
}

One thing I noticed though is that ionChange is called twice using this method when it sets event.checked to false if the condition isn’t met. Is this the best way to handle this currently?

That’s what the outer guard (event.checked != this.chkFoo) is there for. Credit for that portion of this idiom goes to @jasonwaters, see here if interested.

I read that post before creating mine (always research before asking), so I figured that’s what it was doing.

Still, it would be so much neater if we could just prevent the checkbox from being checked rather than checking it then unchecking it.

Thanks for the help and the links!

i tried to do the same in ionic5 and it worked but only for the first time, when i click afterwards, it toggles normally, which it shouldn’t. here’s the code

<ion-checkbox [checked]="itemRow.isChecked" (ionChange)="onChange($event.detail.checked, itemRow)"></ion-checkbox>
onChange(checked:boolean, item:any):void
{
       console.log(checked);

          if (!checked)
          {
               return;
          }

       item.isChecked = false;
}