How to make Next.js links dynamic based on current dynamic page?
Asked Answered
D

2

6

I am building an LMS using Next.js. So far my project structure is localhost/courses/1. Every course will have 7 pages. Dashboard, Assignment, TestAndQuizzes, Gradebook, Resources, Announcements, and Roster. I have all the components and pages ready. So if I manually go to localhost/courses/1/assignments or localhost/courses/1323/roster, etc. works fine.

What I want to do is: When I click on the assignment link, I need to go to the assignment page of that specific course - something like localhost/courses/1/assignments. Currently, I have hard-coded the URL to /courses/1/[page] so if I click assignments it will go to localhost/courses/1/assignment or if I click roster it will go to localhost/courses/1/roster.

How do I make that route dynamic so that when users click on one of the tabs inside a course, it takes them to that page of that specific course?

I looked up next/link and next/router but I still am not able to do that. Any help?

Edit: Here is my folder structure:

enter image description here

Like I said above, for now I have used the links to send someone to /courses/1/assignment for example.

If you want to check out the site it is hosted at My app.

import Image from 'next/image';
import tools from "./sidebarData";
import SideBarItem from "./SidebarItem";

function Sidebar() {
    return (
        <div className="flex mt-8 ml-20">
            <div className="">
                <ul>
                    {Object.entries(tools).map(([key, {title, url, icon}]) => (
                        <SideBarItem key={key} title={title} Icon={icon} url={url}/>
                    ))}
                </ul>

            </div>
        </div>
    )
}

export default Sidebar;

import Link from 'next/link';
import {useState, useEffect} from 'react';

function SidebarItem({title, Icon, url}) {

    const [currentUrl, setCurrentUrl] = useState('');
    
    useEffect(() => {
        setCurrentUrl(window.location.href);
    }), [];

    return (
        <div>
            <li className="flex mb-8 group">
                <div className="shadow-sm p-2 mr-3 rounded-lg"><Icon className="h-8 w-9 hover:animate-bounce" /></div>
                <Link href={`${url}`} ><a className="self-center cursor-pointer transition duration-100 transform hover:scale-125">{title}</a></Link>
            </li>
        </div>
    )
}

export default SidebarItem;

// export tool names and URLs
import {
    AcademicCapIcon,
    HomeIcon,
    BookOpenIcon,
    UserGroupIcon,
    SpeakerphoneIcon,
    FolderOpenIcon,
    QuestionMarkCircleIcon

} from "@heroicons/react/outline";

export default{
    goToHome:{
        title: 'Home',
        url: '/courses/1/',
        icon: HomeIcon,
        component : "dashboard"
    },
    goToAsignments:{
        title: 'Assignments',
        url: '/courses/1/assignments',
        icon: AcademicCapIcon,
        component : "assignment"
    },
    goToTestQuizzes:{
        title: 'Test and Quizzes',
        url: '/courses/1/testAndQuizzes',
        icon:QuestionMarkCircleIcon,
        component : "testAndQuizzes"
    },
    goToGradeBook:{
        title: 'Gradebook',
        url: '/courses/1/gradebook',
        icon:BookOpenIcon,
        component : "gradebook"
    },
    goToResources:{
        title: 'Resources',
        url: '/courses/1/resources',
        icon: FolderOpenIcon,
        component : "resources"
    },
    goToAnnouncements:{
        title: 'Announcements',
        url: '/courses/1/announcements',
        icon:SpeakerphoneIcon,
        component : "announcements"
    },
    goToRoster:{
        title: 'Roster',
        url: '/courses/1/roster',
        icon:UserGroupIcon,
        component : "roster"
    },
}
Dinothere answered 21/10, 2021 at 2:12 Comment(0)
L
2

In your JSON data replace the hardcoded course IDs in the url fields with [courseId], e.g. /courses/[courseId] or /courses/[courseId]/assignments.

You can then use a URL object format in the Link's href to interpolate the [courseId] in the URLs with the current course ID retrieved from router.query.

import Link from 'next/link';
import { useRouter } from 'next/router';

function SidebarItem({ title, Icon, url }) {
    const router = useRouter();

    return (
        <div>
            <li className="flex mb-8 group">
                <div className="shadow-sm p-2 mr-3 rounded-lg"><Icon className="h-8 w-9 hover:animate-bounce" /></div>
                <Link href={{
                    pathname: url,
                    query: { courseId: router.query.courseId }
                }}>
                    <a className="self-center cursor-pointer transition duration-100 transform hover:scale-125">{title}</a>
                </Link>
            </li>
        </div>
    );
}

This should make all links in the sidebar dynamic, based on the current course page the user is on.

Lowbred answered 23/10, 2021 at 22:53 Comment(1)
the new client side router does not support this anymore.. see nextjs.org/docs/messages/app-dir-dynamic-hrefVolkman
H
-1

I would recommend you look at the built in dynamic routing https://nextjs.org/docs/routing/dynamic-routes

In your file structure you can specify your dynamic routing with folders like pages/courses/[id]/assignments.jsx make sure you have the folder name exactly like [id] so its dynamic

Highstrung answered 21/10, 2021 at 2:17 Comment(1)
I just added a picture of my folder structure. And I do have [courseId] as the dynamic folder inside the courses folder. The links that are to be clicked are in a Sidebar component. Do you wanna look at the picture and see if I can do something better there?Dinothere

© 2022 - 2024 — McMap. All rights reserved.