How to dependent dropdown with Laravel Inertia Vue?

53 Views Asked by At

I have AddressController, and inside that controller, i have function loadCity with other CRUD function like this:

public function loadCities(Request $request)
    {
            $provinceId = $request->province_id;
            $cities = Province::where('province_id', $provinceId)->get();

            return response()->json($cities);
    }

And my create.vue script:

<Multiselect v-model="form.province_id" :options="provinces" valueProp="id" label="name" trackBy="name" :searchable="true" placeholder="Select:" @change="loadCities" />

const cities = ref([]); 

const loadCities = async () => {
    try {
        const response = await router.get(`/apps/address/load-cities/${form.province_id}`);
        cities.value = response.data;
    } catch (error) {
        console.error(error);
    }
}

and this is my route web.id:

Route::resource('/address', AddressController::class, ['as' => 'apps'])
    ->middleware('permission:address.index|address.create|address.edit|address.delete')
    ->except(['show']);

        Route::get('/address/load-cities/{province_id}', [AddressController::class, 'loadCities'], ['as' => 'apps'])
        ->name('apps.address.loadCities');

But the problem now is error:

The GET method is not supported for this route. Supported methods: PUT, PATCH, DELETE.

Can i create dependent dropdown using intertia router like this? Or i have something missing with my code? Thanks before.

Update: if i console.log(form.province_id) its return null.

1

There are 1 best solutions below

8
Ahmed Amin Shahin On BEST ANSWER

In your routes file, define the loadCities route using the get method:

 Route::get('/address/load-cities/{province_id}', [AddressController::class, 'loadCities'])->name('apps.address.loadCities');

In your create.vue script, update the loadCities method to make a GET request to the correct route:

const loadCities = async () => {
    try {
        const response = await router.get(`/address/load-cities/${form.province_id}`); // Update the route
        cities.value = response.data;
    } catch (error) {
        console.error(error);
    }
}

You can ensure that the loadCities function is called only after the province_id has been selected. You can achieve this by listening to the input event on the Multiselect component.

<Multiselect v-model="form.province_id" :options="provinces" valueProp="id" label="name" trackBy="name" :searchable="true" placeholder="Select:" @input="handleProvinceChange" />

Then, define the handleProvinceChange method in your Vue component:

const handleProvinceChange = async () => {
    // Check if the province_id is not null or undefined
    if (form.province_id) {
        await loadCities(); // Call the loadCities function
    }
}

Ensure that the loadCities method is defined above the handleProvinceChange method to avoid any reference issues.

In your Vue component, create a watcher for the form.province_id property:

watch: {
  'form.province_id': {
    immediate: true, // Call the handler immediately after the component is created
    handler(newProvinceId, oldProvinceId) {
      if (newProvinceId) {
        loadCities(); // Call the loadCities function when the province_id changes
      }
    }
  }
}