#Nested home screen due to routing issue

15 messages · Page 1 of 1 (latest)

cunning cedar
#

I am new to angular and i am trying to figure out routing system

i have app.routes.ts

import { Routes } from "@angular/router";

export const routes: Routes = [
    {
        path: "",
        loadComponent: () => import("./app").then((m) => m.App),
        resolve: {},
        title: "Login",
    },
    {
        path: "home",
        loadComponent: () =>
            import("./containers/home/home.component").then((m) => m.HomeComponent),
        resolve: {},
        title: "HOME!",
    },
];

my app basically does the authentication with backend:

export class App implements OnInit {
    private authService = inject(AuthenticationService);
    isLoggedIn = signal<boolean>(false);
    constructor() {
        this.authService.initAuth().subscribe({
            next: (res) => {},
            error: alert,
        });
        this.authService.isLoggedIn$.subscribe((isLoggedIn) => {
            this.isLoggedIn.set(isLoggedIn);
        });
    }

    ngOnInit(): void {}
}

my app.html:

@if(isLoggedIn()){
<div class="grid h-dvh w-dvw grid-cols-[auto_1fr] grid-rows-[auto_1fr_auto]">
    <div class="row-span-3">
        <c-sidebar />
    </div>

    <c-header />
    <main class="bg-blue-50">
        <router-outlet></router-outlet>
    </main>
    <c-footer />
</div>

}@else{
<c-login></c-login>
}

for some reason when i log in i get to see main content nested twice:

dense cloud
#

Is ⁨App⁩ also your "root component", i.e. the one you bootstrap in ⁨main.ts⁩? Because if so, of course it'll render twice, because you bootstrap it as the root component (look at ⁨index.html⁩ to see where it will be rendered) and then you also tell the router to render it for the empty route.

cunning cedar
#

yes it is @dense cloud

#

what is the best approach here if i want login to be accessable only when the user is not logged in

dense cloud
#

I am not sure how that is relevant to the issue at hand, to be honest. You need a root component (⁨App⁩) and it contains everything that will always be rendered (for every route), so usually just a bare skeleton and then a ⁨<router-outlet />⁩ (that's where the page contents go).
And then you have a separate component (not ⁨App⁩) for every route (including ⁨path: ""⁩)

cunning cedar
#

the issue here is that i dont want sidebar/footer/header in login page thats why i seperated it and also i dont want user to be able to go to /login directly, and i am not sure if subscription in login page to auth service is good performance wise to keep redirecting calls to home

#

i might be stuiped regarding the last point

#

but ill give this a try and conditionally render the sidebar and header/footer

dense cloud
#

For the first issue, you can use nested child routes and "layout" components, one moment

#

⁨```ts
const routes = [
{
path: ""
component: NoSidebarLayout
children: [
{
path: "login"
component: LoginPage
}
]
},

{
path: ""
component: WithSidebarLayout
children: [
{
path: ""
component: HomePage
},
{
path: "other"
component: OtherPage
},
]
},
];

worldly lark
#

Also: it's weird to have the home page at /home and the login page at /. It should be the home page at /, and the login page at /login.

dense cloud
#

Now in ⁨NoSidebarLayout⁩ and ⁨WithSidebarLayout⁩ you place a second (nested) ⁨<router-outlet />⁩ and that's where the children go

dense cloud
#

And then a very simple login guard could look like this (more or less pseudo-code, because it's not using asynchronous):
⁨```ts
{
path: "",
component: HomePage,
canActivate: [
() => inject(LoginService).isLoggedIn() ? true : new RedirectCommand("/login");
]
}