I am trying to get my head around angular animations. I found an article on how to create an animated menu, so I implemented it. This is what I have so far (I have stripped out code not relevant to this question)
import { Component, AfterViewInit, HostBinding, HostListener, ElementRef, Renderer2, OnInit } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { distinctUntilChanged, filter, map, pairwise, share, throttleTime } from 'rxjs/operators';
import { fromEvent } from 'rxjs';
enum VisibilityState {
Visible = 'visible',
Hidden = 'hidden'
}
enum Direction {
Up = 'Up',
Down = 'Down'
}
@Component({
selector: 'pyb-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss'],
animations: [
trigger('toggle', [
state(
VisibilityState.Hidden,
style({ height: '10px' })
),
state(
VisibilityState.Visible,
style("*")
),
transition('* => *', animate('200ms ease-in'))
])
]
})
export class HeaderComponent implements AfterViewInit, OnInit {
private isVisible: boolean = true;
constructor(
private renderer: Renderer2,
private element: ElementRef
) { }
@HostBinding('@toggle')
get toggle(): VisibilityState {
if (this.isVisible) {
this.renderer.removeClass(this.element.nativeElement, 'collapsed');
}
else {
this.renderer.addClass(this.element.nativeElement, 'collapsed');
}
return this.isVisible ? VisibilityState.Visible : VisibilityState.Hidden;
}
@HostListener('mouseenter')
mouseEnter() {
this.isVisible = true;
}
@HostListener('mouseleave')
mouseLeave() {
this.isVisible = false;
}
ngOnInit() {
}
ngAfterViewInit() {
const scroll$ = fromEvent(window, 'scroll').pipe(
throttleTime(10),
map(() => window.pageYOffset),
pairwise(),
map(([y1, y2]): Direction => (y2 < y1 ? Direction.Up : Direction.Down)),
distinctUntilChanged(),
share()
);
const scrollUp$ = scroll$.pipe(
filter(direction => direction === Direction.Up)
);
const scrollDown = scroll$.pipe(
filter(direction => direction === Direction.Down)
);
scrollUp$.subscribe(() => {
this.isVisible = true
});
scrollDown.subscribe(() => {
this.isVisible = false;
});
}
}
Now, if the template was just something like this:
<div class="header" #header>
</div>
and the CSS was like this:
:host {
height: $header-height;
background-color: $clouds;
color: $midnight;
position: fixed;
top: 0;
width: 100%;
z-index: 1000;
}
Everything appears to be working. But, as soon as I add content, it doesn't work properly. My template actually looks like this:
<div class="header" #header>
<div class="container">
<div class="row">
<div class="col" *ngIf="retailers && count && !displayMatches">
<p class="float-left"><b>{{ count }}</b> {{ category }} available at </p>
<pyb-text-slider [textArray]="retailers"></pyb-text-slider>
</div>
<div class="col" *ngIf="matches && displayMatches">
<span [ngSwitch]="matches.length">
<p *ngSwitchCase="0"><b>{{ matches.length }}</b> {{ category }}</p>
<p *ngSwitchDefault><b>{{ matches.length }}</b> {{ category }} from <b>{{ matches[0].price }}</b></p>
</span>
<pyb-matches></pyb-matches>
</div>
</div>
</div>
</div>
And the problem is, the content does not collapse with the menu. I had to add some CSS:
.header {
visibility: visible;
opacity: 1;
transition: visibility .2s, opacity .2s linear;
padding: 12px 0;
}
&.collapsed .header {
visibility: hidden;
opacity: 0;
}
which hides the content, but this isn't really great. Has anyone come across this before and knows how to fix it?