CodingNic

Creating & Editing Contacts

Wire Up the New and Edit Pages

Creating & Editing Contacts 20 min read

Wire Up the New and Edit Pages

Wire Up the New and Edit Pages

New contact page

Replace the placeholder in app/contacts/new/page.tsx:

tsx
import { createContactAction } from "@/lib/actions";
import ContactForm from "@/components/ContactForm";

export default function NewContactPage() {
  return (
    <>
      <div className="page-heading">
        <h1>New contact</h1>
      </div>
      <ContactForm action={createContactAction} submitLabel="Save contact" />
    </>
  );
}

createContactAction is passed straight through as the form’s action —
no wiring, no event handler.

Edit contact page

Replace the placeholder in app/contacts/[id]/edit/page.tsx:

tsx
import { notFound } from "next/navigation";
import { getContactById } from "@/lib/contacts";
import { updateContactAction } from "@/lib/actions";
import ContactForm from "@/components/ContactForm";

export const dynamic = "force-dynamic";

export default async function EditContactPage({ params }: { params: { id: string } }) {
  const contact = await getContactById(params.id);
  if (!contact) notFound();

  const boundAction = updateContactAction.bind(null, params.id);

  return (
    <>
      <div className="page-heading">
        <h1>Edit {contact.name}</h1>
      </div>
      <ContactForm action={boundAction} contact={contact} submitLabel="Save changes" />
    </>
  );
}

updateContactAction takes two arguments — id and formData — but a
form’s action prop can only pass it one (formData, on submit). .bind(null, params.id)
creates a new function with id permanently attached, so what the form
actually calls behaves like (formData) => updateContactAction(id, formData).
This is the standard pattern for passing extra, fixed arguments into a
Server Action from a specific page.

Add Edit and Delete buttons to the detail page

Open app/contacts/[id]/page.tsx and update the detail-actions div:

tsx
<div className="detail-actions">
  <Link href={`/contacts/${contact.id}/edit`} className="btn btn-ghost">Edit</Link>
  <Link href="/" className="btn btn-ghost">Back to all contacts</Link>
</div>

(Delete stays out for now — it needs a Client Component, which is Module 6.)

Test it

Click “+ Add contact” in the nav bar, fill in a name and a couple of other
fields, and submit. You should land on that new contact’s detail page —
confirming both the create and the redirect worked. Go back to Home; the
new contact should appear in the list, correctly grouped by its first
letter (confirming revalidatePath("/") did its job). Now click “Edit” on
any contact, change a field, and save — you should land back on the detail
page with the updated value showing.

Checkpoint

You can create a new contact from the nav bar and edit any existing one,
using the same form component for both, with no page needing to manually
refetch or reload to see the change.