Reputation: 5226
My website will have a sidebar, header, footer, and content. Something like this:
That's an easy grid I can implement.
But on some pages I want my content to have an additional sidebar on the right. The problem is that I want it to move the header and the footer:
The only solution that I found is to pass the header and the footer into each page. But this is not DRY.
So, how can I do that? Is this even possible? If so, how? I can't even imagine how the final code should look like...
P.S. I read about auxiliary outlets, but don't know how can I apply them to this issue.
Upvotes: 1
Views: 893
Reputation: 2699
Here another answer after I understood your problem a bit better :)
Look at this codepen: https://codepen.io/spierala/pen/wvBWaWV
For the CSS I also used bootstrap flex classes, but the main magic is position: absolute
on the div.content-sidebar
so it can "escape" of its parent container). Also the parent container div.content-container
is not allowed to have positioning itself to make that work.
The app-component must decide over giving footer and header a margin.
The routed component inside the router outlet must decide over the margin of the div.content
. Because div.content-sidebar
is absolute positioned it can not influence the width of div.content
anymore. We have to fix that manually by adding margin if the content-sidebar is visible.
So you can use Angular to add the css classes / styling which are needed for adding or removing the margins in app-component and in the routed components - depending on the content-sidebar visibility.
How will app-component and routed component know? You could introduce a Angular service which will hold the information if a sidebar is visible or not. The routed component could set that information. app-component reads it.
EDIT: regarding the "escape"... if header and footer have fixed heights then you could use negative margins on the content-sidebar instead of the position:absolute approach
If footer and header have a height of 50px then the div.content-sidebar
margins look like this:
.content-sidebar {
margin-top: -50px; // - header height
margin-bottom: -50px; // - min footer height
}
I created another codepen here: https://codepen.io/spierala/pen/PowzmzL
You will also see that div.content
does not need margin anymore since the content-sidebar is not positioned absolute
.
Upvotes: 2
Reputation: 2699
You can also add a data property to your routes (see more info here: https://angular.io/guide/router):
const routes: Routes = [
{
path: 'comp1',
component: Comp1Component,
data: { showContentSideBar: true }
},
{ path: 'comp2',
redirectTo: '/Comp1Component',
data: { showContentSideBar: false }
},
{ path: '',
redirectTo: '/comp1',
pathMatch: 'full'
},
];
In your app-root component you can read that data with the showContentSideBar
flag like this:
constructor(
private router: Router,
private activatedRoute: ActivatedRoute
) {
}
ngOnInit() {
// https://ultimatecourses.com/blog/dynamic-page-titles-angular-2-router-events
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data))
.subscribe((event) => {
console.log(event); // Outputs {showContentSideBar: true} or {showContentSideBar: false}
// write showContentSideBar to a public var and use it for ngIf on sideBar component
});
}
app.component template
<sidebar></sidebar>
<div class="main">
<header></header>
<div class="content><router-outlet></router-outlet></div>
<footer></footer>
</div>
<content-sidebar *ngIf="showContentSideBar"></content-sidebar>
That way you can simply ngIf the content-sidebar
in your app (root) component using the information that you get in the subscribe
. Only one root component/template will be needed for that approach.
Sadly the code to read the data from the route looks a bit bloated, but as far as I know there is no better solution for that. See also on Github: https://github.com/angular/angular/issues/9662
Todd Motto´s solution: https://ultimatecourses.com/blog/dynamic-page-titles-angular-2-router-events
Upvotes: 0
Reputation: 29335
you'd have your wrapper 1 component:
@Component({
selector: 'wrapper-one',
template: `
<sidebar></sidebar>
<div class="main">
<header></header>
<div class="content><router-outlet></router-outlet></div>
<footer></footer>
</div>
`
})
export class WrapperOneComponent { ... }
then wrapper 2:
@Component({
selector: 'wrapper-two',
template: `
<sidebar></sidebar>
<div class="main has-content-sidebar">
<header></header>
<div class="content><router-outlet></router-outlet></div>
<footer></footer>
</div>
<content-sidebar></content-sidebar>
`
})
export class WrapperTwoComponent { ... }
then structure your routes:
[
{
path: '',
component: WrapperOneComponent,
children: [
// all not needing sidebar
]
}
{
path: '',
component: WrapperTwoComponent,
children: [
// all needing sidebar
]
}
]
Upvotes: 1