htmlだけでinputの合計した入力値を出力 Output

#htmlだけでinputの合計した入力値を出力

単純な値の計算であればonClickやonChangeで計算出来ますが複雑な計算だと
以前はjQueryなんかで要素の変更を検知したり、ライブラリーなんかで双方向データバインディングで結果を出力したりしてました

今はhtml5 のinput を使えばjavascriptを使わずに値を計算して結果を出力できることを恥ずかしながらつい最近知りました・・・
html5もcss3もちゃんと把握できていないのを最近痛感しています

## Output属性
今回使うのはhtml5で追加されたOutput要素です
これを使うことでform内の値を計算して出力することが出来ます


# Output - 加算
まずはAとBのinputの要素の加算です
よくあるのが買い物カゴの中身を計算する時とかに使います

## oninput
oninputでform内のフィールドに値が入力された時実行します
その際にoutputに指定したname属性に計算した値の結果を入れています

parseIntで整数にしているのは変換しないと文字列連結になってしまうため整数値に一度変換しています

```html
<form oninput="result.value = (hoge.value && fuga.value) && parseInt(hoge.value) + parseInt(fuga.value)">
  <input type="number" name="hoge"> + <input type="number" name="fuga">
  = <output name="result">
</form>
```

最終的にリファクタするとこんな感じに外部で関数化したもので評価すれば使い回せるはずです

<p data-height="265" data-theme-id="0" data-slug-hash="YYoNeB" data-default-tab="html,result" data-user="HidetoNagamatsu" data-embed-version="2" data-pen-title="html output 1" class="codepen">See the Pen <a href="https://codepen.io/HidetoNagamatsu/pen/YYoNeB/">html output 1</a> by Hideto (<a href="https://codepen.io/HidetoNagamatsu">@HidetoNagamatsu</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
# OutPut 表示要素の切り替え

今度はある一定の合計値以上に文字列を表示してみたいと思います

```html
<script>
  const add = (x,y) => {
    if(!x || !y) return "";       
    x = parseInt(x);
    y = parseInt(y);
    if(x+y < 10){
      return "10より小さい";      
    }
    return "10より大きい"
  }
</script>

<form oninput="result.value = add(hoge.value,fuga.value)">
  <input type="number" name="hoge"> + <input type="number" name="fuga">
  = <output name="result">
</form>
```

value値以外の文字列などのも表示できます
またif文などの判定も使えるので処理によって特定の要素のclassやスタイルを変えることもできます


<p data-height="265" data-theme-id="0" data-slug-hash="LeKyyb" data-default-tab="html,result" data-user="HidetoNagamatsu" data-embed-version="2" data-pen-title="html output 2" class="codepen">See the Pen <a href="https://codepen.io/HidetoNagamatsu/pen/LeKyyb/">html output 2</a> by Hideto (<a href="https://codepen.io/HidetoNagamatsu">@HidetoNagamatsu</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>

# Output エラー時の表示
今度はinputのバリデーションエラーの文言を表示して見たいと思います

```html
<form
  oninput="result.value = hoge.validity.valid ? hoge.value : hoge.validationMessage"
>
  <input type="number" name="hoge" required
    oninvalid="this.setCustomValidity('入力内容が空です')"
    oninput="this.validity.valid ? this.setCustomValidity('') : this.setCustomValidity('入力内容が空です')"
  />
  :<output name="result"></output>
  <div>
    <input type="submit" />
  </div>
</form>
```


## バリデーションメッセージの表示
input要素の `validity` にはバリデーションのフラグ情報が入っています
それを判別して要素が持っているバリデーション用のメッセージを表示します

` oninput="result.value = hoge.validity.valid ? hoge.value : hoge.validationMessage" `

## バリデーションメッセージの変更
`oninvalid`でsubmit時にバリデーションに引っかかればここが発火します
`setCustomValidity`でバリデーションメッセージを書き換えられるので変更します

入力時にも変更したいので`oninput`イベントにも`setCustomValidity`でメッセージを書き換えます
注意しなければいけないのが、下記のように書き換えた場合です

```html
<input type="number" name="hoge" required
    oninput="this.setCustomValidity('入力内容が空です')"
  />
```

`setCustomValidity()`で内容を書き換えると `validationMessage`が書き変わるのですが
`validity.valid`もfalseに変わるため常にバリデーションでエラーが出た状態になってしまいます
なので通常時は `this.setCustomValidity('')` で初期化してあげる必要があります

### 補足
```html:ダメなパターン
<input type="number" name="hoge" required
    oninvalid="this.setCustomValidity('入力内容が空です')"
    oninput="this.validity.valid ? this.setCustomValidity('') : this.setCustomValidity('入力内容が空です')"
  />
```

この内容だと`this.validity.valid`がfalseの時に`this.setCustomValidity()`でメッセージをセットするのはいいけど
その際`validity.valid`もfalseに変わるため常にfalseになってしまっていた。。。(上で全く同じことを自分で説明しているのに・・・)

なので正しくは下記になります

```html:正しいパターン
<input type="number" name="hoge" required
  oninvalid="this.setCustomValidity('入力内容が空です')" 
  oninput="
    this.setCustomValidity('');
    this.validity.valid ? this.setCustomValidity('') : this.setCustomValidity('入力内容が空です')
   "
/>
```
つまり判定処理を入れる前に必ず `this.setCustomValidity('')` で初期化する必要がありました・・・



<p data-height="265" data-theme-id="0" data-slug-hash="aEgwBL" data-default-tab="html,result" data-user="HidetoNagamatsu" data-embed-version="2" data-pen-title="html output 3 error" class="codepen">See the Pen <a href="https://codepen.io/HidetoNagamatsu/pen/aEgwBL/">html output 3 error</a> by Hideto (<a href="https://codepen.io/HidetoNagamatsu">@HidetoNagamatsu</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>


## 複数のバリデーションエラー

まぁ、ただ単にinputとoutputを増やしただけですw
でも一番見るパターンがこれなので一応載せておきます
formの配列を回して作成するとか色々考えましたが多分、これが一番無難な作り方です

<p data-height="265" data-theme-id="0" data-slug-hash="BJXLVp" data-default-tab="html,result" data-user="HidetoNagamatsu" data-embed-version="2" data-pen-title="html output 4 errors" class="codepen">See the Pen <a href="https://codepen.io/HidetoNagamatsu/pen/BJXLVp/">html output 4 errors</a> by Hideto (<a href="https://codepen.io/HidetoNagamatsu">@HidetoNagamatsu</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>


#おまけ

ちなみにCodePenでタブなどの自動整列をしたい場合は全選択したのち shift + tab とかで綺麗になるのでオススメです

![1516958381.gif](https://qiita-image-store.s3.amazonaws.com/0/115192/9552b88b-b0fa-03de-1009-87e6dfcc6df5.gif)