JavaScript mini challenge - solution
Tags: javascript, challenge, programming
Published: 2022-06-26 10:46:55

Hi, coders!

Two days ago I posted [a real world mini challenge](https://dev.to/joolsmcfly/code-with-me-selectpicker-and-max-options-56i7) that I was tasked to implement.

Specifications are simple enough:
>users should be able to select as many cities as they like from a drop down as long as they're not located in more than 2 countries.

## RTFM
As often is the case, reading the documentation goes a long way. This time is no exception.
If you head over to [the events section](https://developer.snapappointments.com/bootstrap-select/options/#events) of the doc you will see that you can listen to `changed.bs.select` which is fired right after the underlying select value changed.

```javascript
$('#mySelect').on('changed.bs.select', function (e, clickedIndex, isSelected, previousValue) {
  // do something...
});
```

What's important here is that we also get `previousValue` which, you guessed it, holds the drop down value before it was changed.
So if we can figure out when a user has selected a third country then we can just set the value back to `previousValue` by doing:
```javascript
$("#cities")
    .selectpicker()
    .on(
        "changed.bs.select",
        function (event, clickedIndex, isSelected, previousValue) {
            const $this = $(this);
            if (someCondition) {  // <== gotta work on this next
                $this.selectpicker('val', previousValue);
            }
        }
    );
```

## Counting how many countries are selected
We don't just want the number of selected cities but the number of countries they belong to.
The only info we have is the `optgroup` label and we'll use just that.

```javascript
const selectedCountries = $this
    .find("option:selected")
    .get()
    .map((o) => $(o).parent().attr("label"))
```
We're basically looping on each selected option and grab their `optgroup`'s label.
The problem is that country names are not unique if more than one city is selected.

If you've been reading JavaScript related posts here on dev.to then you've probably seen the following one liner which gets unique values from `someArray`:
```javascript
const uniqueNames = [new Set(...someArray)];
```

Exactly what we want so let's use it:
```javascript
const uniqueCategories = [
    ...new Set(
        $this
            .find("option:selected")
            .get()
            .map((o) => $(o).parent().attr("label"))
        )
    ];
```

Now that we have a unique list of countries we just need to count the number of elements and if it's greater than 2 then we just set the dropdown's value to `previousValue`.

```javascript
if (uniqueCategories.length > 2) {
    $this.selectpicker('val', previousValue);
}
```

## Putting it all together
```javascript
$(function () {
    const MAX_NUMBER_COUNTRIES = 2;
    $("#cities")
        .selectpicker()
        .on(
            "changed.bs.select",
            function (event, clickedIndex, isSelected, previousValue) {
                const $this = $(this);
                const uniqueCategories = [
                    ...new Set(
                        $this
                            .find("option:selected")
                            .get()
                            .map((o) => $(o).parent().attr("label"))
                    )
                ];

                if (uniqueCategories.length > MAX_NUMBER_COUNTRIES) {
                    $this.selectpicker('val', previousValue);
                }
            }
        );
});
```
See it in action on [CodePen](https://codepen.io/JoolsMcFly/pen/oNEKpNZ).


## Conclusion
Although this "challenge" was not difficult it shows how important it is to read the doc!
Back when I was a student our Java teacher challenged us to write the shortest possible program to manipulate some strings.
Some came up with a 7 lines program. Others had 4 lines.

The teacher's had ONE line. :sparkles:
It was just a call to a native Java function which did exactly what was asked. His way of saying RTFM but in a politically correct way.

Happy coding! :computer: