Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bwrigley's avatar

How to lazy load child component and data

Extremely new to Intertia so I'm not even sure if my question is doable:

In my Laravel project I have a model called Topic which has a relationship back to itself to allow for subtopics, and for those topics to have subtopics etc etc.

I want to have a Vue component that initially displays all of the topic level topics in a tableish style, and when one of those topics is clicked, I want the table to expand to show the child topics, and when one of those children is clicked to show it's children etc.

I'm hoping there is a way to lazy load the children on demand without a full page refresh.

My TopicController index method:

    public function index()
    {

        return Inertia::render('Topic/Index',[
            'topics' => Auth::check() ? Topic::mine()->orderBy('name')->get() : null,
            
        ]);

    }

Query Scope in Topic:

    public function scopeMine($query, $parentId = null)
    {
        return $query->where(['user_id' => Auth::id(), 'topic_id' => $parentId ?? null])->withCount('children');
    }

Topic/Index.vue:

<script setup>

    import Layout from '@/Shared/Layout.vue';
    import TopicBar from '@/Shared/Topic/TopicBar.vue';

    defineProps({
        topics: Array
    });

</script>

<template>
    <Layout title="Topics Index">

        <div class="w-4/5 lg:w-1/2 space-y-3 fixed">
            <div v-for="topic in topics">
                <TopicBar :topic="topic"/>
            </div>
        </div>


    </layout>
</template>

and TopicBar.vue

<script setup>

import { Link } from '@inertiajs/vue3';
import { ref } from 'vue';
import ChevronDown from '../SVG/ChevronDown.vue';

    defineProps({
        topic: Object
    });

    let showChildren = ref(false);

</script>

<template>

    <div
        class="bg-opacity-40 rounded p-2 flex  items-center relative"
        :class="topic.background"
    >
        <div class="truncate w-32">
            {{ topic.name }}
        </div>
        <div class="text-base text-left hidden lg:inline ml-3 truncate w-52">
            {{ topic.description }}
        </div>
        <div class="text-base text-left hidden lg:inline ml-3 truncate w-52">
            {{ topic.children_count }}
        </div>
        <div class=" fill-white absolute right-2" v-if="topic.children_count > 0">
            <ChevronDown width="30" height="30" @click="showChildren = ! showChildren" class="-rotate-90"/>
        </div>
    </div>

    <div v-if="showChildren">
        <!-- <div v-for="child in topic.children">
            <TopicBar :topic="child" />
        </div> -->
    </div>

</template>

I see the documentation refers to the partial reload which is what I suspect I want, but I'm not clear how to lazy load child relationships.

I hope my rambling makes some sense!

TIA

0 likes
7 replies
Snapey's avatar

unless you have thousands of topics, why would you need to lazy load anything?

bwrigley's avatar

@Snapey it's a great point! But actually I'm just playing for learning purposes at the moment, so want to learn how I would pull additional/new backend data into a component without a full refresh :)

m7vm7v's avatar

If I get it right then you could have something like this in your Topic.php

public $with = ['children'];

public function children()
{
    return $this->hasMany(self::class, 'parent_id');
}

But there is the problem of having a recursive function that never ends. Also, there should be protection between pointing a parent to child and child to parent.

bwrigley's avatar

@m7vm7v thanks for the reply.

If I understand your suggestion, this will pass the whole hierarchy to the Vue component wouldn't it?

I'm hoping to find a way to load up children only when the user clicks on a topic so they can be displayed under the clicked topic.

I hope that makes better sense

m7vm7v's avatar

@bwrigley Ahh I see. Then I'd suggest using Ajax calls to retrieve any additional information after the user click event.

bwrigley's avatar

@m7vm7v yeah that's where I'm stuck. I'm asking what Inertia provides to do that in the background.

jlrdw's avatar

@bwrigley

I'm asking what Inertia provides to do that in the background.

Let the database do the work, you can just set up double pagination.

An example would be something like accounts receivable reports where you have a link for next company, underneath that you have that companies receivables paginated.

Normally a search is also set up to drill down into just one company if needed.

Please or to participate in this conversation.