[改良版]JavaScriptで複数のチェックボックスのうち1つでも選択されていたらボタンを有効にする

学習の過程を記載していきます。
完成形は[こちら](#5-完成形)です。
# 1. 前回の完成形
```html:sample.html
<form>
    <label><input type="checkbox" name="sample" value="1" onchange="change()">選択肢1</label><br>
    <label><input type="checkbox" name="sample" value="2" onchange="change()">選択肢2</label><br>
    <label><input type="checkbox" name="sample" value="3" onchange="change()">選択肢3</label><br>
    <input type="submit" id="button" value="送信" disabled>
</form>
```


```js:sample.js
function change() {
	const submitBtn = document.getElementById('button');
	const checkboxes = document.querySelectorAll('input[name="sample"]:checked');
	if (checkboxes.length === 0) {
		submitBtn.disabled = true;
	} else {
		submitBtn.disabled = false;
	}
}
```
[前回の記事](https://qiita.com/katao_eng/items/ffea1575afdc95646995#comment-f8ec07581ec097cc68e9)でこのような実装となりました。
想定通りの挙動となり満足していましたが、ありがたいことにコメントでアドバイスをいただき改善点を教わったので早速取り入れてみました。

>振り分けに必要な条件が**選択済みチェックボックスの有無のみで具体的な個数は不要**なのであれば、`querySelectorAll`で条件に一致する要素を全て取得しなくても`querySelector`で1つ取得できるかどうかだけで判断できると思います。
選択済みチェックボックスがあればその要素のうち最初のひとつが、無ければnullが返ってくるので、それを`!`でbool値に変換及び反転をすることでボタン要素のdisabledプロパティにそのまま渡すこともできますので、ifでの条件分岐も省略できます。

とてもわかりやすいです。
参考にコードもつけていただいていています。
せっかくなので一旦コードを見ずに実装してみて、あとで答え合わせをしてみようと思います。

# 2. boolean型に変換する
いただいたコメントの中で、
>`!`でbool値に変換及び反転

ここが理解できなかったので調べてみました。
辿り着いたのはBooleanメソッドというもので、**引数の真偽を確認し、boolean型の値を返却する**ということでした。

文字列は空文字（""）が`false`でそれ以外は`true`、数値は0が`false`でそれ以外は`true`となります。

```javascript:参考
const a = Boolean("");          //false
const b = Boolean("sample");    //true
const c = Boolean(0);           //false
const d = Boolean(1);           //true
const e = Boolean(null);        //false
```

# 3. 答え合わせ
調べたことを参考に作り直したコードがこちら
```javascript:sample.js
function change() {
	const submitBtn = document.getElementById('button');
	const hasChecked = !Boolean(document.querySelector('input[name="sample"]:checked'));
	submitBtn.disabled = hasChecked;
}
```
とてもスッキリしました。
```javascript
const hasChecked = !Boolean(document.querySelector('input[name="sample"]:checked'));
```
ここでは選択済みになっているチェックボックスの最初の一つの要素（なければnull）を取得し、Booleanメソッドでboolean型の値を`！`で反転させて変数に代入しています。
これならif文で条件分岐させる必要もなくなりました。
かなり自信あります。
答え合わせします。

・・・

全然違う！！！

参考として教えていただいたコードはこちらです。
```js
const f = document.querySelector('form');
f.addEventListener('input', () =>
  f.querySelector('#button').disabled = !f.querySelector('[type=checkbox]:checked'));
```
・・・全くわかりません！笑
少しずつ解明していきます。

# 4. 少しずつ紐解く
```js
const f = document.querySelector('form');
```
まず、form要素を丸ごと取得して変数に代入しています。
```js
f.addEventListener('input', () =>
  // 処理
);
```
アロー関数を使用して`addEventListener`を設定しています。
`addEventListener`では第一引数で指定したイベントが実行されるたびに第二引数で指定した関数が呼び出されます。
ここでは`input`イベントを指定して、チェックボックスが選択されるたびに関数が呼び出されるようになります。
この方法だとチェックボックスのinputタグにonchange属性を指定する必要がなくなります。
```js
f.querySelector('#button').disabled = !f.querySelector('[type=checkbox]:checked')
```
ここで送信ボタンを非活性とするかどうかを指定します。
`f.querySelector('[type=checkbox]:checked')`で選択済みになっているチェックボックスの最初の一つの要素（なければnull）を取得しているのですが、ここではboolean型に変換する必要があります。
しかし、「[2. boolean型に変換する](#2-boolean型に変換する)」で習得したBooleanメソッドを使用していません。
`!`を使用することで暗黙の型変換が行われるようです。
>`!`でbool値に変換及び反転

というのはこういうことだったのだと理解できました。
```js:参考
f.querySelector('[type=checkbox]:checked')    // 最初の要素 or null

!f.querySelector('[type=checkbox]:checked')   // false or true
```
# 5. 完成形
```js:sample.html
<form>
  <label><input type='checkbox' value='1'>選択肢1</label><br>
  <label><input type='checkbox' value='2'>選択肢2</label><br>
  <label><input type='checkbox' value='3'>選択肢3</label><br>
  <input type='submit' id='button' value='送信' disabled>
</form>

<script>
const f = document.querySelector('form');
f.addEventListener('input', () =>
  f.querySelector('#button').disabled = !f.querySelector('[type=checkbox]:checked'));
</script>
```
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="BarBymG" data-user="katao_eng" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/katao_eng/pen/BarBymG">
  Untitled</a> (<a href="https://codepen.io/katao_eng">@katao_eng</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

とてもシンプルなコードですが内容が詰まっていてとても勉強になりました。
アドバイスいただき本当にありがとうございました。
これを自力で実装できる実力にはまだまだ至りません。

- 関数
- アロー関数
- addEventListener
- querySelector

そもそも基本的な知識がまだまだ足りていません。
次回はJavaScriptの基礎を習得してまとめていきたいと思います。

# 参考記事
[JavaScriptのboolean型に変換する方法を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン](https://techacademy.jp/magazine/25793)
[【JavaScript】addEventListenerの使い方](https://qiita.com/mzmz__02/items/873118fbd8723c44956d)
[JavaScript | inputイベント：フォームで文字が入力されたとき](https://www.javadrive.jp/javascript/event/index24.html)
[EventTarget.addEventListener() - Web API | MDN](https://developer.mozilla.org/ja/docs/Web/API/EventTarget/addEventListener)
[論理否定 (!) - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Logical_NOT)
[型変換のいろいろ - Qiita](https://qiita.com/zawascript/items/a25eaf7a222ac3671275)
[暗黙的な型変換 · JavaScript Primer #jsprimer](https://jsprimer.net/basic/implicit-coercion/)