Categories
Laravel

Dual-use Conditional Laravel Controller Methods for Inertia + Vue

Dual-use controllers in Laravel serve a dual purpose: they return/render an Inertia/Vue page when accessed normally and JSON data when requested via AJAX (e.g., with Axios).

This is super useful when you need to reload props data in your Vue component.

Example

I will create a controller method that serves an Inertia/Vue page and conditionally a JSON response.

Controller (Laravel)

use Illuminate\Http\Request;
use App\Models\YourModel;

public function myPage()
{
    $data = YourModel::find(1);

    if (!$data) {
        $data = [
            'message' => 'Hello, Inertia and Vue!',
            'counter' => 0,
        ];
    }

    if (request()->wantsJson()) {
        return response()->json($data);
    }

    return inertia('MyPage', [
        'data' => $data,
    ]);
}

public function store(Request $request)
{
    $model = new YourModel();
    $model->message = $request->input('message');
    $model->counter = $request->input('counter');
    $model->save();

    return response()->json(['message' => 'Data saved successfully']);
}

So the method checks if the request is for JSON. If it is, respond with plain JSON; otherwise, serve the ‘MyPage’ Inertia/Vue view with the data.

Vue Component (MyPage.vue)

<template>
  <div>
    <h1>{{ form.message }}</h1>
    <p>Counter: {{ form.counter }}</p>
    <button @click="incrementCounter">Increment Counter</button>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { useForm, usePage } from '@inertiajs/vue3';

const { props } = usePage();
const form = useForm({
    message: '',
    counter: 0
});

const incrementCounter = () => {
    form.counter++;
    axios.post(route('myroute'), form).then(response => {
        if (response.data?.message) {
            form.message = response.data.message;
        }
        if (response.data?.counter) {
            form.counter = response.data.counter;
        }
    });
};

onMounted(() => {
    if (props.data?.message) {
        form.message = props.data.message;
    }
    if (props.data?.counter) {
        form.counter = props.data.counter;
    }
    // Reload data (needed for back button)
    axios.get(route('myroute')).then(response => {
        if (response.data?.message) {
            form.message = response.data.message;
        }
        if (response.data?.counter) {
            form.counter = response.data.counter;
        }
    });
});
</script>

The Vue Component uses the onMounted lifecycle hook to fetch data via Axios when the page loads, ensuring that the component works seamlessly even when the page is served from the browser cache, e. g. when using the browser’s back button.

Leave a Reply

Your email address will not be published. Required fields are marked *