Next.js Discord

Discord Forum

Handle Communication Between Component in layout.tsx (Nav Bar) and Other Pages

Answered
Tan posted this in #help-forum
Open in Discord
TanOP
I have a bottom Navigation Bar and I can go BACK and NEXT. When I click NEXT I basically use the router to go to the next path, for example page-1 to page-2. The Navigation Bar is just responsible for changing pages and so I placed it inside the layout.tsx so it stays across all pages...

How can I validate the data of the user If I go from page-1 to page-2. I'm new to NextJS but I feel stuck...

It would be nice to have a validate function fire on each page when I click next, but I have no idea how to achieve this... And ChatGPT is not helping 🥲
Answered by Tan
I finally made it! I used:
- useContext: to get the navigationBar component and be able to invoke functions like next or back
- eventEmitter: to listen for next and back events from nevigation bar.

On every page now I listen for next events, I validate the data (in this case a simple checkbox) and then move to the next step... It works for me, I hope It's the right approach!
View full answer

11 Replies

TanOP
This is the thing I want to achieve
TanOP
Thanks for the reply but maybe I didn't explain it well:
1 - The user is on /page1
2 - The user didn't check the terms on /page1
3 - When the user clicks NEXT I have to somehow check that the terms on /page1 is checked before moving to /page2
4 - Of course if the user clicks on NEXT and didn't checked the box it will show an error message and it will not go to /page2
5 - How can I check this? The bottom nav bar (BACK - NEXT) is on layout component and is rendered on top of every page and /page1 - /page2 are 2 different routes

I hope this is clear or maybe I didn't understand.
@Tan Thanks for the reply but maybe I didn't explain it well: 1 - The user is on /page1 2 - The user didn't check the terms on /page1 3 - When the user clicks NEXT I have to somehow check that the terms on /page1 is checked before moving to /page2 4 - Of course if the user clicks on NEXT and didn't checked the box it will show an error message and it will not go to /page2 5 - How can I check this? The bottom nav bar (BACK - NEXT) is on layout component and is rendered on top of every page and /page1 - /page2 are 2 different routes I hope this is clear or maybe I didn't understand.
Silver Fox
assume you have a input type="checkbox", then
const [checked, setChecked] = useState(false)

const onChange = () => setChecked(!checked) 

return (<input type="checkbox" onChange={onChange}/>)

when the user clicked on the next button, you can do
const onClick = () => checked ? router.push("/page-2") : setError("Agree to the terms before moving ahead!")

did I understand you correctly?
TanOP
Yess this is pretty much what I want to do. But how do I get the onClick event since the NavigationBar is not in /page1 but is on layout.tsx?
TanOP
This is my navigation-bar.tsx it's only responsible for going back and next using an array:
'use client'
import React, { useEffect, useState } from 'react'
import { logger } from '@/utils/logger'
import { usePathname, useRouter } from 'next/navigation'

type NavLink = {
    path: string
    replace: boolean
}

const navLinks: NavLink[] = [
    { path: '/test-navigation/page-1', replace: false },
    { path: '/test-navigation/page-2', replace: false },
]

const NavigationBar = () => {
    const router = useRouter()
    const pathname = usePathname()
    const getNavLinkIndex = () => {
        return navLinks.findIndex((x) => x.path === pathname)
    }
    const [index, setIndex] = useState<number>(getNavLinkIndex())
    const updatePathIndex = () => {
        const pathIndex = getNavLinkIndex()
        setIndex(pathIndex)
        logger.log('NavigationBar :: updatePathIndex :: ' + pathIndex)
    }

    const switchPage = (idx: number) => {
        if (idx > navLinks.length - 1) {
            logger.warn(
                'NavigationBar :: Index is greater than current navigation length'
            )
            return
        }

        if (idx < 0) {
            logger.warn('NavigationBar :: Index is less than zero')
            return
        }

        setIndex(idx)
        const navLink = navLinks[idx]?.path
        router.push(navLink)
        logger.log('NavigationBar :: switchPage :: ' + navLink)
    }

    const next = () => {
        const nxt = index + 1
        logger.log('NavigationBar :: next :: ' + nxt)
        switchPage(nxt)
    }
    const back = () => {
        const nxt = index - 1
        logger.log('NavigationBar :: back :: ' + nxt)
        switchPage(nxt)
    }

    useEffect(updatePathIndex, [pathname])

    return (
        <div className="flex justify-between bg-green-300 p-6 ">
            <button onClick={back}>BACK</button>
            <button onClick={next}>NEXT</button>
        </div>
    )
}

export default NavigationBar
Is mounted on the root layout:
export default function RootLayout({
    children,
}: {
    children: React.ReactNode
}) {
    return (
        <html lang="en">
            <body className={`${inter.className} h-screen-svh flex flex-col`}>
                <Providers>
                    <div className="flex-1">{children}</div>
                    <NavigationBar />
                </Providers>
            </body>
        </html>
    )
}


You say on page1 I can get the Next button (using the id for example) and subscribe onClick event right?
Silver Fox
yes
TanOP
I finally made it! I used:
- useContext: to get the navigationBar component and be able to invoke functions like next or back
- eventEmitter: to listen for next and back events from nevigation bar.

On every page now I listen for next events, I validate the data (in this case a simple checkbox) and then move to the next step... It works for me, I hope It's the right approach!
Answer
TanOP