[SOLVED] Max number of selectable checkboxes

Hello everyone,

I’m new to the Aurelia Framework, I find it quite amazing and like very much the vanilla side of it, and I’m working on a project right now, but I have a question, I would like to know what is the best practice way of limiting the number of checkbox a user can choose out of a certain number:

ChooseSauceModal.html
<label class="container-checkbox"
repeat.for="sauce of sauces">
${sauce.name}
<input type="checkbox" id="${sauce.id}"
click.delegate="add(sauce)"
matcher.bind="sauceMatcher"
checked.bind="sauce.checked"
disabled.bind="sauce.disabled"><span class="checkmark"></span>
</label>

ChooseSauceModal.ts
add(sauce){
sauce.checked = true;
}
sauceMatcher = (a, b) => a.id === b.id;

First I know something is not working already, as I cannot select any checkbox. If I add a return true to the add() function then checkbox perform normally. But I want to make sure that no more that 2 checkboxes can be selected at any time and all not selected after >= 2 become disabled.

Any help would be greatly appreciated,
Thank you.

1 Like

Refer this example: http://aurelia.io/docs/binding/checkboxes#array-of-objects to have the correct binding. You don’t need the click.delegate explicitly unless it has a different purpose.

For limiting the selection, you can add validation. There is a validation rule named maxItems specifically for this use case. Refer: http://aurelia.io/docs/plugins/validation#defining-rules

1 Like

Thank you for your reply, I’m progressing:

ChooseSauceModal.html
<label class="container-checkbox"
repeat.for="sauce of sauces">
${sauce.name}
<input
type="checkbox"
model.bind="sauce"
checked.bind="selectedSauces">
<span class="checkmark"></span>
</label>

EDITED: I was missing init of validator, still not working though
ChooseSauceModal.ts
// Inside class
private sauces: Sauce[] = ApiService.getSauces();
private selectedSauces: Sauce[] = [];
// constructor
constructor(private controller: DialogController,
private vControllerFactory: ValidationControllerFactory){
this.controller = controller;
this.vController = vControllerFactory.createForCurrentScope();
this.vController.validateTrigger = validateTrigger.change;
}
//outside class
ValidationRules.ensure("selectedSauces").maxItems(2);

This seems alright but the validation is not taking place though. Also once this works I would like to change the label color based on wheter its corresponding checkbox works. I’ve seen example but it requires a instead of a wrapping label, which I absolutely need for styling.

Thank you.

1 Like

Great!!

In short, you are missing couple of things.

  1. Use the validate binding behavior in your view to mark the selectedSauces property. It would look something like this selectedSauces & validate. This instructs the validation controller to validate the property.
  2. Define the rules properly. The ValidationRules chain needs to end with an .on(arg) where arg will be this or ChooseSauceModal depending on where you are defining the rules.
  3. Lastly on submit don’t forget to call the controller.validate() to perform a overall validation.

Even if this suggestion works, it is always good to take a look at the validation docs to use it correctly.

1 Like

Ok I’ve tried various thing after reading the docs. But I am not closer unfortunately, as I understand this validator is to validate member of classes. In my case each checkbox is its own instance of Sauce class, but I don’t want to validate any of its member, rather the number of instances (checked boxes).

Apparently adding to the repeated.for input the following:
checked.bind="selectedSauces"
Creates a array of Sauce with only the selected one, good.

Now I get the number of checked boxes, but I would like to watch the change, so I tried:
@observable( {changeHandler: 'selectedSaucesChanged'})
private selectedSauces: Sauce[] = [];
selectedSaucesChanged(newValue, oldValue){
console.log("change")
}
But it only fires once (why ?) and not anymore when I click on any boxes… So close.

1 Like

So the problem actually was observing changes on an array of an object, Sauce[].
As per doc
https://aurelia.io/docs/binding/observable-properties#observing-collections
I need a collection observer:
this.bindingEngine.collectionObserver(this.selectedSauces)
.subscribe(this.selectedSaucesChanged.bind(this))
and its corresponding callback function:
selectedSaucesChanged(splices: Array<ICollectionObserverSplice<string>>){console.log("change"); }

This works. Now I will play around with the splice and the array length to disable all non selectedSauces checkbox. This is looking good, thank you.

3 Likes