formの中でのbuttonタグにつけたリンクが思ったような挙動をしてくれなかった時の対処と原因について


## この記事で書くこと
こんばんは。 :night_with_stars: 
もう早いもので今年ももう少しになりました。師走ですね。

今回は、気を抜くと忘れてしまいそうな `form` 内で使用される `button` の挙動について残したいと思います。
アウトプットしてもう忘れないことが狙いです。

## formの中で使われる buttonタグの挙動

よくある以下のようなインターフェイスを例にあげます。
formの中に書いてあるsubmitボタンと、それ以外のボタン。
（イメージしやすくするように、コードを書いているので、動作するコードでない可能性があります。ご了承ください。 :bow: ）

![スクリーンショット 2019-12-05 18.59.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71266/81c3c8e6-621f-c2ff-5d8b-8e5b3c17b8d2.png)

「登録する」右側のボタンを押すと、**フォームの内容がsubmitされます。後述する内容を意図して書いているかは横においておいて。
（今回バリデーションで弾かれて、というようなことは話したいことの外なので考慮していません。）**

```html
<!-- 何かサービス上で、登録する画面 -->
<form action="register_to_team" method="post">
  <button>登録する</button>
  <!-- もしくは以下のようにinputタグも一般的かと思います。 -->
  <input type="submit" value="登録する">
</form>
```


では、「マイページに戻る」が以下のようなコードだった場合、どうなるか、です。
両方とも、 `/mypage.html` に飛ばそうとしています。通常のリンクとして機能させたいようですね。（(もちろん) `Get` です。）

```html
<!-- 何かサービス上で、登録する画面 -->
<form action="register_to_team" method="post">
  <a href="/mypage.html">
    <button>マイページに戻る</button>
  </a>
  <!-- もしくは -->
  <button>
    <a href="/mypage.html">マイページに戻る</a>
  </button>
</form>
```

ただ、このボタンはどちらも期待した挙動（ `/mypage.html` へのリンク ）をしてくれません。
むしろ、「登録する」を押した挙動になってしまいます。これは困った。思わぬバグを生んでしまいます。

でも、何故でしょうか？ :thinking: 



## buttonタグ

[HTML5タグリファレンス](http://www.htmq.com/html5/button.shtml) をきちんと確認します。

> type属性はボタンの種類を指定する際に使用します。 type属性の値には、以下の３種類のいずれかを指定することができます。 初期値はtype="submit"です。
type="submit" …… フォーム入力内容を送信するサブミットボタン（初期値）
type="reset" …… フォーム入力内容をリセットするリセットボタン
type="button" …… 何もしない汎用的な押しボタン
form属性は、どのフォームと関連付けるかを指定する際に使用します。 <button>は初期値では直近の親要素となる<form>と関連付けられますが、 <form>のid属性の値と<button>のform属性の値を一致させることで、 ボタンを特定のフォームと関連付けることができます。 ボタンを任意の場所に配置できるので、ウェブアプリケーションなどを制作する際には便利かもしれません。

以下の２箇所に注目です。

①
> 初期値はtype="submit"です。

②
> buttonは初期値では直近の親要素となる<form>と関連付けられます

なるほど。

今回「マイページに戻る」のボタンを想定して書かれているコードは、type属性をbuttonに指定していません。
つまり **type="submit"** ということですね。
初期値をあえて入れた状態で見てみます。
特に、idなども設定しておらず、親要素となる `<form>` と紐付けられるわけですから、書いた通りの、親要素のaction先である、 `register_to_team` にsubmitしてしまっていた、ということです。

以下のいづれかも、正常に、 `/mypage.html` へリンクすることができるかと思います。

```html
<!-- 何かサービス上で、登録する画面 -->
<form action="register_to_team" method="post">
  <a href="/mypage.html">
    <button type="button">マイページに戻る</button>
  </a>
  <!-- もしくはちょっとクリックする箇所が狭いですが、今度は一応動きますよ。 -->
  <button type="button">
    <a href="/mypage.html">マイページに戻る</a>
  </button>
  <!-- もしくはbuttonタグに拘らずに、divなどのタグを使用する。 -->
  <a href="/mypage.html">
    <div class="button_style">マイページに戻る</div>
  </a>
</form>
```

ここまで来ると、「会員登録」のボタンがどちらも、submitされるのはきちんと理解できる準備が整いました。


```html
<!-- 何かサービス上で、登録する画面 -->
<form action="register_to_team" method="post">
  <button>登録する</button>
  <!-- もしくは以下のようにinputタグも一般的かと思います。 -->
  <input type="submit" value="登録する">
</form>
```

これは以下のように解釈されていました。ですから、buttonでも確かにsubmitされていた、というわけです。


```html
<!-- 何かサービス上で、登録する画面 -->
<form action="register_to_team" method="post">
  <button type="submit">登録する</button>
  <!-- もしくは以下のようにinputタグも一般的かと思います。 -->
  <input type="submit" value="登録する">
</form>
```

忘れてしまいがちですが、特に他の人が書いたコードであっても、formの中で使われる `<button>` には注意したいです。


## buttonタグのformaction属性について

この属性を知らなかったので、ついでに調べてみました。

[caniuse.com](https://caniuse.com/#search=formaction)
[HTML5タグリファレンス](http://www.htmq.com/html5/button.shtml) 

> formaction属性（送信先URL）・ formenctype属性（送信するデータの形式）・ formmethod属性（送信方法）・ formnovalidate属性（入力されたデータの妥当性を確認しない）・ formtarget属性（フォーム送信するターゲット先）は、 <form>の属性でも同様の指定をすることができますが、 <button>側でこれらの属性を指定すると、<form>の指定より優先されます。

> formaction属性・formenctype属性・formmethod属性・formnovalidate属性・formtarget属性は、 type="submit"の場合にのみ指定することができます。

どうやら、 `<button>` に設定すると、formに設定された内容を上書きすることができるようです。ボタン毎に、submit先が異なる場合は、有効そうです。
今回は、ただ単にlinkさせたいだけなので `<a>タグ` で対応しましたが、以下のようにも書ける、ということですね。
 
```html
<!-- 何かサービス上で、登録する画面 -->
<form action="register_to_team" method="post">
  <button formaction="mypage.html" formmethod="get">マイページに戻る</button>
</form>
```

## 最後に
悩んだ時は、ドキュメントに戻る、というのを大事にしていて良かった。
もし間違ってる点や、より良い解決方法などありましたら、コメントいただければ幸いです。 :bow: 
それでは。 :door: