3

I'm building an Angular 2 app and need two layout files. One for the logged out users... (Login/Register views etc) and one for the logged in users to see the actual app itself. How can this be achieved with Angular 2?

Currently I have an app.component.html that simply has

<main-navbar></main-navbar>
<router-outlet></router-outlet>

But what I need to do is something along the lines of:

<div [ngSwitch]="layout">

  <template [ngSwitchCase]="panelLayout">
      /* output all the html layout elements for the logged out views */
      <router-outlet></router-outlet>
  <template>

  <template [ngSwitchCase]="appLayout">
     /* output all the html elements for the in logged in/app views */
     <router-outlet></router-outlet>
  </template>

</div>

But I have no idea where or how to set the layout variable.

I'm presuming this variable would best be set inside the main view component... or is there a better way to do this?

Mel
  • 5,837
  • 10
  • 37
  • 42
markstewie
  • 9,237
  • 10
  • 50
  • 72
  • Possible duplicate of [How to switch layouts in Angular2](https://stackoverflow.com/questions/38780436/how-to-switch-layouts-in-angular2) – Mel Oct 24 '17 at 08:40
  • You can try this [Multiple layout in angular 2](https://stackoverflow.com/questions/38780436/how-to-switch-layouts-in-angular2/38783451#38783451). Hope it helps. Been using it for a while now and it scales very well no matter the number of layout your would want to use in your app – oseintow Aug 05 '16 at 07:38

3 Answers3

2

I worked out what I was trying to achieve by using transclusion... as far as I can see this isn't mentioned anywhere in the official docs!

It's simply a case of using <ng-content></ng-content> in the layout files where the main content for each layout needs to go.

// eg: app-layout.html
<app-header></app-header>
<app-navbar></app-navbar>
// content using this layout will appear below
<ng-content></ng-content>
<app-footer></app-footer>

Then after importing and including in directives use the layout it in a view like

// eg: dashboard.html
<app-layout>
  <h1>Hello {{user}}!</h1>
</app-layout>

Hope this helps someone trying to achieve the same thing

markstewie
  • 9,237
  • 10
  • 50
  • 72
  • 3
    Man sorry but this is totally not clear to understand. The example feels unfinished. – tkit Nov 10 '17 at 21:16
1

I recommend you to switch your view with different routes, i.e., one route for the logged in users that resolves to a component A and another route for users that aren't logged in that resolves to a component B.

I prefer to use this strategy because you can block users in the route level using the CanActivate hook, i.e., before going to a particular route, there's a validation. If it's false, the user won't access that route. If it's true, the route is activated.

You can read the awesome documentation about how to use the CanActivate here in the Routing & Navigation: CanActivate Guard documentation.

Hope it helps.

Bernardo Pacheco
  • 1,445
  • 1
  • 14
  • 23
  • I'm already using the CanActivate guard method to redirect users to the `/login` route if not logged in but I want to know how to create reusable layout files that are used for multiple routes depending on which route/view component is active. – markstewie Aug 03 '16 at 02:57
  • If I've got the point, do you want to use the same html file with different components that are shown in different routes? – Bernardo Pacheco Aug 03 '16 at 03:15
  • Yes, that's right. So the "logged out" layout would simply show a logo and then the nested route view of either a login form or registration form and the "logged in/app" layout would have the main app navigation and then show the content of each app route inside of that... hope that makes sense? – markstewie Aug 03 '16 at 03:39
  • In my opinion is better to separate the concerns, i. e., create a component and a route to deal with the sign in and register process and another component and route to deal with the logged in app. And here we use what I suggested about the can activate guard that you said you're using. This guard is only used in the authenticated routes. Separating in this way is much easier to maintain a large application. – Bernardo Pacheco Aug 03 '16 at 03:55
  • Ok, I get what you're saying now I think... so there are two main components and each would have nested routes... right? – markstewie Aug 03 '16 at 03:58
  • A proposal could be: route `/signin` mapped to a `SignInComponent`, route `/register` mapped to a `RegisterComponent` and route `/` with a `CanActivate` guard mapped to a `DashboardComponent`. If an unauthorized user tries to access the `/` route, the `CanActivate` guard redirect to the `/signin` route. – Bernardo Pacheco Aug 03 '16 at 04:18
0

Just inject a shared service that provides the current loggedIn status to the component.

@Injectable()
class AuthService {
  isLoggedIn = new BehaviorSubject(false);

  ...      
}
bootstrap(AppComponent, [..., AuthService]);
@Component({
  template: `
<div [ngSwitch]="authService.isLoggedIn | async">

  <template [ngSwitchCase]="false">
      /* output all the html layout elements for the logged out views */
      <router-outlet></router-outlet>
  <template>

  <template [ngSwitchCase]="false">
     /* output all the html elements for the in logged in/app views */
     <router-outlet></router-outlet>
  </template>

</div>
`
})
class MyComponent {
  constructor(private authService:AuthService) {};
}

See also Make AJAX request before bootstrapping Angular2 application

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • I appreciate your answer and that would certainly work but for the size of app I'm building using the transclusion in seperate layout files as described above is my preferred solution as it keeps things seperate and tidy and using a guard to protect routes. – markstewie Aug 04 '16 at 09:06
  • Is this the best approuch to handle multiple layouts in angular 2? Like a login page with a simple layout and the other pages with other layout – Diego Unanue Sep 12 '16 at 19:21
  • You can use the router to show various views. This is just to dispay a single component in various ways. – Günter Zöchbauer Sep 12 '16 at 19:23
  • In my app.component I've got this when I navigate to login I want to get rid of the but for all other pages when the user is logged in I just want to display the layout as it is. Do I have to use ng-if with a service to archieve this? What's the best way? Do you have a link or something to help me I've stucked on this for days. – Diego Unanue Sep 12 '16 at 20:10
  • `*ngIf` and a service sounds right for this use case – Günter Zöchbauer Sep 13 '16 at 05:02