inertia
inertia copied to clipboard
Component not updating after post request to Laravel from Vue
Versions:
Laravel 9 "@inertiajs/inertia": "^0.11.0", "@inertiajs/inertia-vue3": "^0.6.0"
Describe the problem:
- the Vue component makes a post request to the Laravel backend.
- the Laravel router calls the controller correctly
- the controller gets the collection correctly and calls Inertia::render
- the component doesn't update - no evidence of any activity or errors seen
Steps to reproduce:
// Search.vue
Inertia.post(
`/centres/search/${props.type}`,
{ search: value },
{ preserveScroll: true }
);
// web.php
Route::post('/centres/search/{type}', [CentresController::class, 'search'])->name('centres.search');
// CentresController.php
// THE METHOD CALLED BY THE ROUTER:
public function search(Request $request, string $type)
{
$search = $request->input('search');
$filters = new \stdClass();
$filters->search = $search;
$this->search_text( $filters );
}
// THIS METHOD DOES NOT SEEM TO BE ABLE TO CALL inertia::render()
public function search_text($filters)
{
$centres = Centre::query()
->when($filters->search, function ($query, $search) {
$query->where('name', 'like', '%' . $search . '%')
->OrWhere('address', 'like', '%' . $search . '%')
->OrWhere('email', 'like', '%' . $search . '%')
->OrWhere('notes', 'like', '%' . $search . '%');
})
->with('resources')
->paginate($this->pagination);
// dd($centres); >>> outputs the correct collection as expected
// THIS SEEMS TO FAIL, BUT NO ERROR MESSAGES OR EVIDENCE THAT IT WAS CALLED
return Inertia::render('Centres/Centres', [
'type' => 'text',
'filters' => $filters,
'centres' => $centres,
'distances' => [],
]);
}
After hours of testing, I realised that the return Inertia::render() call had to come from the same function as the one called by the router - then it works as expected. The search_text() function perhaps doesn't have access to some part of the Inertia workings?
Solution:
The following works, by calling return Inertia::render from within the same controller method - search() - that the router called:
public function search(Request $request, string $type)
{
$search = $request->input('search');
$filters = new \stdClass();
$filters->search = $search;
$centres = Centre::query()
->when($filters->search, function ($query, $search) {
$query->where('name', 'like', '%' . $search . '%')
->OrWhere('address', 'like', '%' . $search . '%')
->OrWhere('email', 'like', '%' . $search . '%')
->OrWhere('notes', 'like', '%' . $search . '%');
})
->with('resources')
->paginate($this->pagination);
// THIS NOW WORKS AND THE COMPONENT IS UPDATED CORRECTLY
return Inertia::render('Centres/Centres', [
'type' => 'text',
'filters' => $filters,
'centres' => $centres,
'distances' => [],
]);
}
FULL CODE
Full component code in case useful ... note that the Intertia.post() call came from Search.vue, a subcomponent of Centres.vue
// Centre/Centre.vue
<template>
<AppLayout title="Centres">
<template #header>
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Centres
</h2>
</template>
<div class="max-w-7xl mx-auto py-10 sm:px-6 lg:px-8">
<h2 class="text-xl font-bold mb-5">Find centres</h2>
<Search :type="type" :filters="filters" />
<div class="flex gap-4 mt-3">
<div>
<input type="radio" id="location" value="location" v-model="type" />
<label class="ml-2" for="location">Location</label>
</div>
<div>
<input type="radio" id="text" value="text" v-model="type" />
<label class="ml-2" for="text">Text</label>
</div>
</div>
</div>
{{centres}}
<!-- <Map :centres="centres" /> -->
<!-- <List :centres="centres" :filters="filters" :distances="distances"/> -->
</AppLayout>
</template>
<script setup>
import { ref, reactive, watch } from 'vue';
import AppLayout from '@/Layouts/AppLayout.vue';
import { Inertia } from "@inertiajs/inertia";
import Search from '@/Components/Centres/Search.vue';
import Map from '@/Components/Centres/Map.vue';
import List from '@/Components/Centres/List.vue';
const props = defineProps({
type: {
type: String,
default: 'location',
},
filters: {
type: Object,
default: () => ({}),
},
centres: {
type: Object,
default: () => ({}),
},
distances: {
type: Array,
default: []
},
});
const type = ref(props.type);
</script>
// Search.vue
<template>
<div>
<p>Filters: {{ filters }}</p>
<input v-model="search" type="text" :placeholder="'Search ' + type + '...'"/>
</div>
</template>
<script>
import { Inertia } from "@inertiajs/inertia";
import { ref } from "vue";
import { watch } from "vue";
export default {
components: {
},
props: {
type: {
type: String,
default: '',
},
filters: {
type: Object,
default: () => ({}),
},
},
setup (props) {
let search = ref(props.filters.search);
watch(search, (value) => {
Inertia.post(
`/centres/search/${props.type}`,
{ search: value },
{
preserveScroll: true,
}
);
});
return {
search
}
}
}
</script>
Hey @narkan,
the problem is that you are not returning from your controller method, so the Inertia response is never returned.
// CentresController.php
// THE METHOD CALLED BY THE ROUTER:
public function search(Request $request, string $type)
{
$search = $request->input('search');
$filters = new \stdClass();
$filters->search = $search;
/***************************
* Here you need to return
***************************/
return $this->search_text( $filters );
}
// THIS METHOD DOES NOT SEEM TO BE ABLE TO CALL inertia::render()
public function search_text($filters)
{
$centres = Centre::query()
->when($filters->search, function ($query, $search) {
$query->where('name', 'like', '%' . $search . '%')
->OrWhere('address', 'like', '%' . $search . '%')
->OrWhere('email', 'like', '%' . $search . '%')
->OrWhere('notes', 'like', '%' . $search . '%');
})
->with('resources')
->paginate($this->pagination);
// dd($centres); >>> outputs the correct collection as expected
// THIS SEEMS TO FAIL, BUT NO ERROR MESSAGES OR EVIDENCE THAT IT WAS CALLED
return Inertia::render('Centres/Centres', [
'type' => 'text',
'filters' => $filters,
'centres' => $centres,
'distances' => [],
]);
}
Hey! Thanks so much for your interest in Inertia.js and for sharing this issue/suggestion.
In an attempt to get on top of the issues and pull requests on this project I am going through all the older issues and PRs and closing them, as there's a decent chance that they have since been resolved or are simply not relevant any longer. My hope is that with a "clean slate" me and the other project maintainers will be able to better keep on top of issues and PRs moving forward.
Of course there's a chance that this issue is still relevant, and if that's the case feel free to simply submit a new issue. The only thing I ask is that you please include a super minimal reproduction of the issue as a Git repo. This makes it much easier for us to reproduce things on our end and ultimately fix it.
Really not trying to be dismissive here, I just need to find a way to get this project back into a state that I am able to maintain it. Hope that makes sense! ❤️