1つのフォームに複数の投稿ボタンがあるのは稀なことではありません。例えば、「保存」と「キャンセル」ボタンとか、ウィザードなら確認画面において「入力に戻る」と「確定」ボタンとか、結構2つのボタンが存在することあります。さらに、編集画面では「保存」、「削除」、「キャンセル」と3つのボタンのケースも。今回はそれらの対応に関しての話です。

「戻る」ボタン(投稿ボタンではない)

例えば、会員登録において、入力画面、確認画面、完了画面の3つの画面からなるウィザードであるとき、真ん中の確認画面では、最初の入力画面へ「戻る」ボタンと、次の完了画面に行く「確定」ボタンが必要です。

「戻る」ボタンの対応で、一番簡単なのは以下のようなjavascriptでの対応です。

<button onclick="window.history.back()">入力に戻る</button>

onclickの部分は、以下でも同じことです。

<button onclick="window.history.go(-1)">Go Back</button>
<button onclick="history.back()">Go Back</button>

しかし、このボタンはフォームの中にあっても、フォームに投稿(POST)するわけではないので投稿ボタンとは言えないですね。

リダイレクトのボタン(これも投稿ボタンではない)

例えば、以下のように「保存」と「キャンセル」ボタンがあるとき、「キャンセル」ボタンではリダイレクトを使用できます。

これもjavascriptを使用するなら、

<button onclick="location.href='{{ route('home') }}'" type="button">キャンセル</button>

Bootstrapを利用するなら、cssでリンクをボタンにもできます。

<a class="btn" href="{{ route('home') }}">キャンセル</a>

これもフォームの投稿ボタンとは言えないですね。

「保存して新規」のボタン(これは投稿ボタン)

このボタンは、例えば会員において複数の届け先を連続して入力してもらう、とかでの使用ケースあります。つまり、1つの届け先を登録してもらうなら「保存」ボタン1つでいいところ、複数の届け先を連続して登録したいときに、「保存」と「保存して新規」の2つのボタンを装着します。

「保存して新規」のボタンを押したら現在の入力を保存してから、空の新規の画面を表示します。

この場合は、今までのケースとは違って、「保存」あるいは「保存して新規」のボタンのクリックは、両方とも現在入力されたデータの保存のためにPOSTの実行、つまりフォームの投稿が必要となります。それゆえに、コントローラで投稿を受けるメソッドではどちらのボタンがクリックされたかの区別が必要となります。

まずは、ブレードではこんな感じです。

...
<form method="POST" action="{{ route('register') }}">
	@csrf

	<div class="form-group row">
		<label for="name" class="col-md-4 col-form-label text-md-right">名前</label>

		<div class="col-md-6">
			{{ $name }}
		</div>
	</div>

...

	<div class="form-group row mb-0">
		<div class="col-md-6 offset-md-4">
			<input type="submit" class="btn btn-primary" name="submit" value="保存">
			<input type="submit" class="btn btn-primary" name="submit_new" value="保存して新規">
		</div>
	</div>
</form>

2つのボタンはともに投稿ボタンです。どちらかがクリックされたかをコントローラで区別するには、


...
class RegisterController extends Controller
{
    public function store(Request $request)
    {
     // 新規の届け先のレコードを保存する処理を行う

     // 新規画面に戻る
        if ($request->has('submit_new')) {
            return redirect()->route('register');
        }

        // ホームに戻る
    return redirect()->route('home');
}

...

というように、ボタンのnameがリクエストに入ってくるので、それで区別できます。

これで解決と思いきや、巷では、<input>のタグでなく<button>のタグの方がデザイナーに好まれます。なぜなら、以下のようにボタンにアイコンを埋め込むことが容易にできるからです。

<button type="submit">
  <i class="fas fa-search"></i> 検索
</button>

それでは、<input><button>に変えてみます。

...
	<button type="submit" class="btn btn-primary" name="submit" value="submit">保存</button>
	<button type="submit" class="btn btn-primary" name="submit_new" value="submit_new">保存して新規</button>
...

あるいは、以下のようにformactionの属性を使用することも可能です。

...
	<button type="submit" class="btn btn-primary">保存</button>
	<button type="submit" class="btn btn-primary" formaction="{!! route('register', 'edit') !!}">保存して新規</button>
...

formactionで指定するURLに(ここでは同じフォーム)に、?editの引数を追加して投稿してくれるので、

...
     // 新規画面に戻る
        if ($request->has('edit')) {
            return redirect()->route('register');
        }

とコントローラで区別して対応することが可能となります。

By khino