Search code examples
phplaraveldropdown

Nested resource controllers and routes with ajax


I used the following code for web.php.

Route::resource('products', 'ProductController');
Route::resource('products.galleries', 'GalleryController');

In this address http://localhost:8000/admin/products , I added this code

<td><a href="{{ route('products.galleries.create', $product->id) }}">Create</a></td>

Then I defined it in create method, and control of GalleryController

GalleryController.php

public function create(Product $product)
{
    return view('Admin.galleries.create', compact('product'));
}

The gallery is empty

I am using dropdown

$.ajax({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
    },
    type: 'POST',
    url: '{{ route('products.galleries.destroy', [$product->id, $gallery->id]) }}',
    date: {filename, name},
    success: function (data) {
        console.log('File has been successfully removed!!');
    },
    error: function (e){
        console.log(e);
    },
});

I get this error

Undefined variable: gallery

Can anyone tell me how to solve this problem?


Solution

  • In your GalleryController, a gallery instance ($gallery) is never sent to the view:

    public function create(Product $product)
    {
        return view('Admin.galleries.create', compact('product')); // where is $gallery ?
    }
    

    This is why in your view, when you are trying to use $gallery (in your javascript, the destroy route), you get an error.

    You have multiple ways to fix this, depending on what you are exactly trying to achieve. However, without more information, the fastest solution would be to wrap your javascript code inside a condition.

    @isset($gallery)
        $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
            },
            type: 'POST',
            url: '{{ route('products.galleries.destroy', [$product->id, $gallery->id]) }}',
            date: {filename, name},
            success: function (data) {
                console.log('File has been successfully removed!!');
            },
            error: function (e){
                console.log(e);
            },
        });
    @endisset
    

    I presume you did it this way because you want to reuse this part of the view when a $gallery variable is available, for instance products.galleries.index or products.galleries.show.

    By wrapping the javascript in @isset($gallery) tags, you'll ensure it will only be executed when a $gallery instance is available.