#Weird behavior with Laravel Inertia + Vuejs (Converting existing Blade project to Vuejs)

25 messages · Page 1 of 1 (latest)

proven inlet
#

I've been playing around with Laravel using blade exclusively, but now I would like to venture my way into Inertia + Vuejs but I am having some trouble.
I was trying to display the value of the $totalAccounts variable to the user and it only works when I have the code inside the route like so:

Route::get('/dashboard', function () {

        $user = Auth::user();
        $totalAccounts = $user->accounts()->count();

        return Inertia::render('Dashboard', [
            'totalAccounts' => $totalAccounts,
        ]);

    })->name('dashboard');

As soon as I extract the code into a controller such as DashboardController the whole page loads but its all blank for some reason.

I change the route to be something like:

Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard.index');

And this is the index() method of the DashboardController:

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;
use App\Models\User;
use App\Models\Account;
use Illuminate\Http\Request;
use Inertia\Inertia;

class DashboardController extends Controller
{
    public function index()
    {
        // Get the currently authenticated user
        $user = Auth::user();

        // Count the total accounts for the authenticated user
        $totalAccounts = $user->accounts()->count();

        return Inertia::render('Dashboard', [
            'totalAccounts' => $totalAccounts,
        ]);
    }
}
#

This is how I've done to retrieve the variable into the .vue:

Dashboard.vue

<script setup>
import AppLayout from "@/Layouts/AppLayout.vue";
import Welcome from "@/Components/Welcome.vue";
</script>

<template>
    <AppLayout title="Dashboard">
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Dashboard
            </h2>
        </template>

        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                    <Welcome :totalAccounts="totalAccounts" />
                </div>
            </div>
        </div>
    </AppLayout>
</template>

<script>
export default {
    data() {
        return {
            totalAccounts: 0, // Default value
        };
    },
    mounted() {
        this.totalAccounts = this.$page.props.totalAccounts; // Assign the value from the prop
    },
};
</script>

Welcome.vue

<script setup>
import ApplicationLogo from "@/Components/ApplicationLogo.vue";
</script>

<template>
    <div>
        <div class="p-6 lg:p-8 bg-white border-b border-gray-200">
            <ApplicationLogo class="block h-12 w-auto" />

            <p class="mt-6 text-gray-500 leading-relaxed">
                FinTrackr is a lightweight personal finance management app for
                tracking debits, credits, and expenses with visually pleasing
                dynamic charts.
            </p>
        </div>

        <div class="bg-gray-200 bg-opacity-25 p-6 lg:p-8">
            <div>
                <div class="flex items-center mb-4">
                    <h2 class="ml-3 text-xl font-semibold text-gray-900">
                        <a>Dashboard</a>
                    </h2>
                </div>
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6 lg:gap-8">
                    <div
                        class="px-4 py-5 bg-white sm:p-6 shadow sm:rounded-tl-md sm:rounded-tr-md"
                    >
                        <p class="font-thin">Total Accounts</p>
                        <h1 class="text-2xl mt-2 font-black">
                            {{ totalAccounts }}
                        </h1>
                    </div>

                    <div
                        class="px-4 py-5 bg-white sm:p-6 shadow sm:rounded-tl-md sm:rounded-tr-md"
                    >
                        <p class="font-thin">Overall Balance</p>
                        <h1
                            class="text-2xl {{ \App\Models\Account::overallTotal() < 0 ? 'text-red-500' : 'text-green-500' }}"
                        >
                            <!-- ${{ \App\Models\Account::overallTotal() }} -->
                        </h1>
                    </div>
                </div>

                <div
                    class="px-4 py-5 bg-white sm:p-6 shadow sm:rounded-tl-md sm:rounded-tr-md mt-8"
                >
                    <p class="font-thin">Analytics</p>
                    <h1 class="text-2xl">
                        Placeholder for the Pie Chart
                    </h1>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    props: {
        totalAccounts: {
            type: Number,
            required: true,
        },
    },
};
</script>

If anyone would be able to help me out it would be greatly appreciated, I can provide further details if necessary.

restive hare
#

here you are returning accounts return inertia('Account/Index', compact('accounts')); but in your frontend you have the prop as totalAccounts

proven inlet
restive hare
#

Ps if you're doing it new I recommend the vue 3 approach...

<script setup>

const props = defineProps({
    accounts: Object,
});

</script>
proven inlet
#

Done, I've updated the controller to the right one, my mistake

proven inlet
restive hare
#

Also I don't know for sure with vue 2 that you have here but with Inertia with and vue 3 $page.props.totalAccounts the $page will take props that you set in the HandleInertiaRequests.php so if it's not there then also will be empty.. but from what i see you don't really want it from there anyway

#

as it's short i've edited the dashboard file below

#
<script setup>
import AppLayout from "@/Layouts/AppLayout.vue";
import Welcome from "@/Components/Welcome.vue";

const props = defineProps({
    totalAccounts: Array //this may be Object not 100%
});
</script>

<template>
    <AppLayout title="Dashboard">
        <template #header>
            <h2 class="font-semibold text-xl text-gray-800 leading-tight">
                Dashboard
            </h2>
        </template>

        <div class="py-12">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
                    <Welcome :totalAccounts="totalAccounts ?? 0" />
                </div>
            </div>
        </div>
    </AppLayout>
</template>
proven inlet
#

So, instead of doing this on the Welcome.vue file:

<script>
export default {
    props: {
        totalAccounts: {
            type: Number,
            required: true,
        },
    },
};
</script>

I should just do it at the <script setup> as you mentioned? There is no need to define it's type nor requirement?

restive hare
#

so what i put above is the dashboard file (completed) - in the controller you change it back to like the first one you posted like this return Inertia::render('Dashboard', compact('totalAccounts'));

restive hare
#

so indeed identical to the first one

proven inlet
#

Oh got it, I will definitely test that out later

#

In this case, totalAccounts is just the result of the sum of the users banking accounts created on the website essentially

restive hare
#

ok hope it helps 🙂 you can see already the shorter syntax with vue 3...

proven inlet
proven inlet
#

@restive hare Hey, sorry to bother you but I just tested it and it works like a charm. The syntax really is way cleaner now.

The only question I have is that one of the problems persists, if in my web.php routes I use something like:

Route::get('dashboard', [DashboardController::class, 'index'])->name('dashboard.index');
#

It his the index() method of the DashboardController.php

#

Loads the page but the page seems to be blank

#

The only way for it to actually work was for me to get the logic of the index() method and extract it into the web.php route statement

#

Just like this:

Route::get('/dashboard', function () {

        $user = Auth::user();
        $totalAccounts = $user->accounts()->count();

        return Inertia::render('Dashboard', compact('totalAccounts'));

    })->name('dashboard');
}
limpid slate