Search code examples
phplaravelvue.jsinertiajslaravel-jetstream

Laravel 8 Jetstream Inertia All Inertia requests must receive a valid Inertia response


I've been trying to find the correct answer for my problem I know that the question has been asked before here and actually many other places, but no answers I found could suit my problem.

The vue component

FooterNewsletter.vue

<template>
    <div class="lg:w-2/4 md:w-1/2 w-full px-8 border-l-2">
        <p class="font-bold text-3xl">
            Don't want to miss the latest cryptocurrency news?
        </p>
        <p class="py-3 text-lg">
            Get the latest news and updates by subscribing to our free
            newsletter 📰
        </p>
        <form @submit.prevent="subscribeToNewsletter">
            <div class="flex flex-col">
                <div class="flex">
                    <input
                        v-model="form.email"
                        type="text"
                        name="post_title"
                        class="
                            border-primary
                            focus:border-primary
                            focus:ring-offset-transparent
                            focus:ring-transparent
                        "
                        id="exampleFormControlInput1"
                        placeholder="Your E-mail"
                    />
                    <input
                        type="submit"
                        value="Subscribe"
                        :disabled="form.processing"
                        class="px-5 py-2 bg-primary text-white cursor-pointer"
                    />
                </div>
            </div>
        </form>
    </div>
</template>

<script>

export default {
    props: [],
    components: {

    },
    data() {
        return {
            form: this.$inertia.form({
                email: "",
            }),
        };
    },
    methods: {
        subscribeToNewsletter() {
            this.form
                .transform((data) => ({
                    ...data,
                    // remember: this.form.remember ? "on" : "",
                }))
                .post(this.route("newsletter.store"), {
                    onSuccess: (data) => {
                        console.log("data", data);
                    },
                    onError: (data) => {
                        console.log("data", data);
                    },
                });
        },
    },
};
</script>

The controller

NewsletterController.php

namespace App\Http\Controllers;

use App\Http\Requests\NewsletterStoreRequest;
use App\Models\Newsletter;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;

class NewsletterController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(NewsletterStoreRequest $request)
    {
        return response()->json([
            'message' => 'suss',
        ]);
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}

The request file

NewsletterStoreRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class NewsletterStoreRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'email' => ['required', 'max:150', 'email'],
        ];
    }
}

The Route

web.php

Route::post('/newsletter', [
    NewsletterController::class,
    'store',
])->name('newsletter.store');

In the sample above i return a json object, which is not accepted and gives me this error enter image description here

I have tried following the inertia documentation about responses here I think the correct answer is to be found there, I have not been able to solve it on my own

I have also looked into inertia Jetstream docs without any luck here

I don't want to return a new view, I actually want it to work as an ajax request I guess where a call-back is either giving me the error or success without reloading the page or anything like that.

I see that many people have this problem, does anyone know whats going wrong and what i have to return in the controller?


Solution

  • For me i had to change the controller to this:

    namespace App\Http\Controllers;
    
    use Inertia\Inertia;
    use App\Models\Newsletter;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Redirect;
    use App\Http\Requests\NewsletterStoreRequest;
    
    class NewsletterController extends Controller
    {
        /**
         * Display a listing of the resource.
         *
         * @return \Illuminate\Http\Response
         */
        public function index()
        {
            //
        }
    
        /**
         * Show the form for creating a new resource.
         *
         * @return \Illuminate\Http\Response
         */
        public function create()
        {
        }
    
        /**
         * Store a newly created resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        public function store(NewsletterStoreRequest $request)
        {
            Newsletter::create([
                'email' => $request->email
            ]);
    
            return back()->with('flash', [
                'message' => 'success',
            ]);
        }
    
        /**
         * Display the specified resource.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function show($id)
        {
            //
        }
    
        /**
         * Show the form for editing the specified resource.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function edit($id)
        {
            //
        }
    
        /**
         * Update the specified resource in storage.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function update(Request $request, $id)
        {
            //
        }
    
        /**
         * Remove the specified resource from storage.
         *
         * @param  int  $id
         * @return \Illuminate\Http\Response
         */
        public function destroy($id)
        {
            //
        }
    }
    

    What you should note here is this part:

        return back()->with('flash', [
            'message' => 'success',
        ]);
    

    I found a sample where my problem was achieved with the help from a friend of mine in: vendor/laravel/jetstream/src/Http/Controllers/Inertia/ApiTokenController.php

    Here they return with a flash message like my example above, the message key will be in props->components->flash->message

    enter image description here

    It won't work as I thought like ajax, because it uses Vue routes so the page will reload on submit.

    I hope someone will find this useful.

    Also if you get a console error because you use data in a vue component you have to make a check on the wrapper to check if the data is null like so:

    <ul
       v-if="assets != null"
       class="
       marketcap-rows
       border-l border-r border-gray-200
       flex flex-col
       "
       >
       <li
          v-for="asset in $props.assets.data"
          v-bind:key="asset"
          class="
          bg-white
          grid
          gap-4
          border-t border-gray-200
          "
          >
       </li>
    </ul>
    

    This is the check I'm talking about: v-if="assets != null"