Next.js Discord

Discord Forum

Allow users to edit an inline editable component?

Answered
Somali posted this in #help-forum
Open in Discord
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/
Answered by European sprat
You make it a client component with a form input
View full answer

5 Replies

Answer
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
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!