So i try to create a update article feature, and this is the code:
ArticleController:
public function update(Request $request, Article $article)
{
$request->validate([
'title' => 'required',
'body' => 'required',
'thumbnail' => 'nullable|mimes:png,jpg,jpeg',
]);
// If new thumbnail uploaded
if ($request->hasFile('thumbnail')) {
$thumbnail = $request->file('thumbnail')->store('thumbnail');
$article->update([
'title' => $request->title,
'body' => $request->body,
'thumbnail' => $thumbnail
]);
} else {
// No new thumbnail
$article->update([
'title' => $request->title,
'body' => $request->body,
]);
}
return redirect('/admin');
}
and this is the view in inertia react:
import React, { useState } from "react";
import Navbar from "../components/Navbar";
import { Editor } from "@tinymce/tinymce-react";
import { useForm } from "@inertiajs/inertia-react";
export default function EditArticle({ article }) {
const { data, setData, patch, errors, reset, processing } = useForm({
title: article.title,
body: article.body,
thumbnail: null
});
const [isOpen, setIsOpen] = useState(false);
function onSubmitEventHandler(e) {
e.preventDefault();
patch(`/articles/${article.id}/edit`, { onSuccess: () => reset() });
}
function openModalEventHandler() {
setIsOpen(!isOpen);
}
function handleThumbnailChange(e) {
setData('thumbnail', e.target.files[0]);
}
return (
<>
<Navbar />
<form className="mt-24" onSubmit={onSubmitEventHandler} encType="multipart/form-data">
{
isOpen &&
<>
<div className="fixed inset-0 flex items-center justify-center z-40">
<div className="p-4 rounded-lg flex flex-col bg-white text-black z-50 relative">
<div onClick={openModalEventHandler} className="hover:cursor-pointer absolute -top-2 -right-2 shadow-md p-2 bg-white rounded-full">
<img src="/icon/closeIcon.svg" className="w-4" alt="Close Icon" />
</div>
<h2 className="text-2xl font-semibold">Edit Article</h2>
<label htmlFor="title" className="mt-5 text-sm">Title:</label>
<input type="text" id="title" className="rounded-lg border py-2 px-3" value={data.title} onChange={(e) => setData('title', e.target.value)} />
<label htmlFor="thumbnail" className="mt-5 text-sm">Thumbnail:</label>
<input type="file" className="mt-2" id="thumbnail" onChange={handleThumbnailChange} />
<button type="submit" disabled={processing} className={`mt-4 py-2 px-4 bg-darkerBlue rounded-lg text-white ${processing && 'opacity-25'}`}>Save Article</button>
{errors.title &&
<p className="mt-2 text-sm text-red-700">{errors.title}</p>
}
{errors.body &&
<p className="mt-2 text-sm text-red-700">{errors.body}</p>
}
{errors.thumbnail &&
<p className="mt-2 text-sm text-red-700">{errors.thumbnail}</p>
}
</div>
<div onClick={openModalEventHandler} className="fixed inset-0 bg-black opacity-35"></div>
</div>
</>
}
<Editor
apiKey='5d3gmavobfl1gplfh7eithg9chuj3shiru72msgp1kescjzi'
init={{
toolbar: 'undo redo | blocks fontfamily fontsize | bold italic underline strikethrough | table | addcomment showcomments | align lineheight | checklist numlist bullist indent outdent | charmap | removeformat',
height: 520,
}}
value={data.body}
onEditorChange={(newValue, editor) => setData('body', newValue)}
/>
<div onClick={openModalEventHandler} className="hover:bg-gray-200 hover:cursor-pointer bg-white transition fixed right-3 bottom-5 rounded-full p-4 card-shadow">
Save
</div>
</form>
</>
)
}
When i only edit the title or the body fields the are no errors..
But when i try to upload file and submit the form there's an error:
The title field is required. The body field is required.
Even though i have filled the title and body fields.
UPDATED
Since uploading files using a multipart/form-data request is not natively supported, you must use a POST
request instead of PATCH
or PUT
.
Or you can try method spoofing by doing :
useForm({
title: article.title,
body: article.body,
thumbnail: null,
_method: "patch" // Add _method to payload
});
post(`/articles/${article.id}/edit`, {
onSuccess: () => reset()
})
Or you can use router:
import { router } from '@inertiajs/react'
router.post('/articles/${article.id}/edit', {
...data,
_method: "patch",
});
Here's the official documentation: