Allow users to edit an inline editable component?
Answered
Somali posted this in #help-forum
SomaliOP
I am trying to create a basic note-taking app with the App Router, MongoDB and Mongoose, how would I allow the user to make an edit to one of the arr.map server components (in other words, a note entry) and then save the results on our database? I want to let the user edit the entry directly on the same page rather than redirecting the user to a dedicated note page.
I'm stuck on the NextJs documentation and was wondering if I should go with Parallel Routes and use a Modal component (https://nextjs.org/docs/app/building-your-application/routing/parallel-routes) or if I should use Intercepted Routes (https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes) to achieve this?
Here is the tutorial I was following along:
https://youtu.be/wNWyMsrpbz0
Would this be possible with NextJs alone or would I need to install npm packages?
I'm likely wording this question wrong, my apologies for that.
Thank you!
*Edit: I found a blog describing this feature https://blog.logrocket.com/build-inline-editable-ui-react/
I'm stuck on the NextJs documentation and was wondering if I should go with Parallel Routes and use a Modal component (https://nextjs.org/docs/app/building-your-application/routing/parallel-routes) or if I should use Intercepted Routes (https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes) to achieve this?
Here is the tutorial I was following along:
https://youtu.be/wNWyMsrpbz0
Would this be possible with NextJs alone or would I need to install npm packages?
I'm likely wording this question wrong, my apologies for that.
Thank you!
*Edit: I found a blog describing this feature https://blog.logrocket.com/build-inline-editable-ui-react/
5 Replies
European sprat
Some edit button which then shows the edit field, save submits to your server
@European sprat You make it a client component with a form input
SomaliOP
Thank you! I was able to come up with the following:
# page.js
# page.js
import Editable from "./Editable";
const getNotes = async () => {
try {
const res = await fetch("http://localhost:3000/api/notes", {
cache: "no-store",
});
if (!res.ok) {
throw new Error(`Failed to fetch notes. Error: ${res.status}`);
}
// const data = await res.json();
return res.json();
} catch (error) {
console.log(`Error while loading notes, ${error}`);
}
};
export default async function Home() {
const { notes } = await getNotes();
return (
<>
{notes.map((note) => (
<div key={note._id}>
<Editable
id={note._id}
title={note.title}
description={note.description}
/>
</div>
))}
</>
);
}# component Editable.js
"use client";
import { useState } from "react";
import RemoveBtn from "@/app/RemoveBtn";
export default function Editable({ id, title, description }) {
const [newTitle, setNewTitle] = useState(title);
const [newDescription, setNewDescription] = useState(description);
const onNotFocus = async (e) => {
e.preventDefault();
try {
const res = await fetch(`/api/notes/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ newTitle, newDescription }),
});
if (!res.ok) {
throw new Error(`Failed to update note. Error: ${res.status}`);
}
router.refresh();
} catch (error) {
console.log(`Error while updating note, ${error}`);
}
};
return (
<div className="px-6 py-8 my-3 flex items-center justify-between bg-slate-700 border border-slate-300">
<textarea
className="resize-none break-words hover:bg-[#d3d3d3] hover:cursor-pointer focus:bg-[#d3d3d3] focus:placeholder-transparent bg-transparent placeholder-slate-900 placeholder-opacity-80 font-semibold text-slate-100"
placeholder="Enter Title"
type="text"
aria-label="Field Title"
value={newTitle}
onChange={(e) => setNewTitle(e.target.value)}
onBlur={onNotFocus}
/>
<textarea
className="resize-none break-words hover:bg-[#d3d3d3] hover:cursor-pointer focus:bg-[#d3d3d3] focus:placeholder-transparent bg-transparent placeholder-slate-900 placeholder-opacity-80 font-semibold text-slate-100"
placeholder="Enter Description"
type="text"
aria-label="Field Description"
value={newDescription}
onChange={(e) => setNewDescription(e.target.value)}
onBlur={onNotFocus}
/>
<RemoveBtn id={id} />
</div>
);
}European sprat
well done!