Shrinkable header

Hi, I have a sample where is the header shrinks when the user scrolls up… however when scrolling down the header does not appear until it reaches the top… How to improve the code when scrolling down some distance, the header should appear

.ts:

    import { Directive, ElementRef, Renderer } from '@angular/core';

    @Directive({
      selector: '[header-shrink]',
      host: {
        '(ionScroll)': 'onContentScroll($event)'
      }
   })
  export class HeaderShrink {
      header: any;
      headerHeight: any;
      translateAmt: any;

   constructor(public element: ElementRef, public renderer: Renderer) { }

   ngAfterViewInit() {
  
     this.header = document.getElementsByClassName("shrinkable")[0];
     this.headerHeight = this.header.clientHeight;
   }

   onContentScroll(ev) {
     ev.domWrite(() => {
        this.updateHeader(ev);
    });
  }

 updateHeader(ev) {

   if (ev.scrollTop >= 0) {
     this.translateAmt = -ev.scrollTop / 4;
  
   } else {
      this.translateAmt =ev.scrollTop / 4;
 }

   this.renderer.setElementStyle(this.header, 'webkitTransform', 'translate3d(0,' + this.translateAmt + 'px,0)');

  }
 }

.html:

 <ion-header class="shrinkable">
   <ion-navbar>
    <button ion-button menuToggle>
    <ion-icon name="menu"></ion-icon>
  </button>
  <ion-title>
     Jobs
   </ion-title>
 <ion-buttons end>
   <button ion-button end icon-only (click)="presentPopover($event)">
  <ion-icon name="more"></ion-icon>
</button>
</ion-buttons>

Can someone help ! thanx… Also how can I add a gradual item fading when the header is shrinking I want it to have a fading effect as well, it would be great if someone can show that

this is exactly what I have…from Ionic 1, i want ionic 2. the code i have posted above works alright, i just want someone to show me how to tweak it

Try this. Based on some code I found here: jfsemaan GitHubGist

.ts

    import { 
    Directive,
    ElementRef,
    Renderer
} from '@angular/core';

@Directive({
    selector: '[shrink-header]',
    host: {
        '(ionScroll)': 'onContentScroll($event)'
    }
})
export class ShrinkHeader {

    header: any;
    headerHeight: any;
    translateAmt: any;
    scrollPosition: number = 0;
    lastScrollTop: number = 0;

    constructor(public element: ElementRef, public renderer: Renderer) {

    }

    ngAfterViewInit() {
        // ion-header classname
        this.header = document.getElementsByClassName("hello")[0];

        // the height of the header
        this.headerHeight = this.header.clientHeight;
    }

    onContentScroll(ev) {
        ev.domWrite(() => {
            this.updateHeader(ev);
        });   
    }
 
    updateHeader(ev) {

      this.scrollPosition = ev.scrollTop;

      if (this.scrollPosition > this.lastScrollTop && this.scrollPosition >= 25) {
        // scrolling down
        this.renderer.setElementStyle(this.header, 'transition', 'all 0.3s linear');
        this.renderer.setElementStyle(this.header, 'transform', 'translateY(-' + this.headerHeight + 'px)');
      } else {
        // scrolling up
        this.renderer.setElementStyle(this.header, 'transform', 'translateY(0px)');
      }

      // reset
      this.lastScrollTop = this.scrollPosition;

    }


 
 
}

.html:

    <ion-header>


  <ion-navbar class="hello">
    <ion-title>A Page</ion-title>
  </ion-navbar>

</ion-header>


<ion-content padding fullscreen shrink-header>
 
 
  <p>lots of content..</p>
 
 
</ion-content>

Hi, thank you for taking the time… your solution works fine but only on one component/page… when I added it to other pages , it does not function at all, Im not really sure why this happens!

Yeah sorry, I’m pretty new to Ionic myself.

The reason this is happening is probably because there’s multiple headers in the DOM. Ionic has it’s own header inside each page, rather than one header outside the pages.

Having a different header for each page is a design decision we’ve made. In Ionic 1, a common issue was that having a single header/navbar wasn’t flexible enough for people.

I’d rather there was just one header, personally. I’ll probably be going down the custom header component road myself.

In the meantime, since there’s multiple headers, it’s best when calling “getElementsByClassName()” to tell it what header to select in context of the page in view; we want to select the the active page > header. we don’t want to search the document level in this case. If we import the NavController we can the active page from that guy (ViewController would probably do it too)

Here’s an update.
shrink-header.ts:

import { 
    Directive,
    ElementRef,
    Renderer
} from '@angular/core';

import { NavController } from 'ionic-angular';

@Directive({
    selector: '[shrink-header]',
    host: {
        '(ionScroll)': 'onContentScroll($event)'
    }
})
export class ShrinkHeader {

    header: any;
    headerHeight: any;
    translateAmt: any;
    scrollPosition: number = 0;
    lastScrollTop: number = 0;
    activePage: any;

    constructor(public element: ElementRef, public renderer: Renderer, public navCtrl: NavController) {
    }

    ngAfterViewInit() {

        // lets get the active page's view controller
        this.activePage = this.navCtrl.getActive()._cmp;

        // let's select the header of the active page
        this.header = this.activePage._nativeElement.getElementsByClassName("hello")[0];

        // the height of the header
        this.headerHeight = this.header.clientHeight;
    }

    onContentScroll(ev) {
        ev.domWrite(() => {
            this.updateHeader(ev);
        });   
    }
 
    updateHeader(ev) {

      this.scrollPosition = ev.scrollTop;

      if (this.scrollPosition > this.lastScrollTop && this.scrollPosition >= 25) {
        // scrolling down
        this.renderer.setElementStyle(this.header, 'transition', 'all 0.3s linear');
        this.renderer.setElementStyle(this.header, 'transform', 'translateY(-' + this.headerHeight + 'px)');
      } else {
        // scrolling up
        this.renderer.setElementStyle(this.header, 'transform', 'translateY(0px)');
      }

      // reset
      this.lastScrollTop = this.scrollPosition;

    }


 
 
}
2 Likes

thanks man , you are brilliant… how did you come by the solution so fast :stuck_out_tongue:
this worked fine on all the pages I updated, only one page didn’t function , but its ok… I hope i know how to learn more about manipulating DOM

1 Like

Cheers man! Just had loads of situations like this in the past when you’ve got loads of pages in the DOM - with various other frameworks.

Be warned though, I think this approach to DOM manipulation in Angular is frowned upon. Like I said, I’m really new to this and I don’t know any other way to do things at this point.

I’ve just been chucked in the deep end with no time to learn (cry for me)

Hopefully Ionic will include this out-of-the-box soon, as well as sliding tabs! (my next nightmare)

C

1 Like

Thank you for the code, I have a small update:

  • a year later the this.activePage has a bit different structure now it should be
    this.header = this.activePage.location.nativeElement.getElementsByClassName("hello")[0];

  • class="hello" should be part of <ion-header>