typescriptionic3anchor-scroll

Ionic v3 Segment - Change active segment while scrolling


I was recently wondering why one can not change the active segment in ionic v3 by modifying the [(ngModel)] within ionScroll.subscribe(). I have my segment content stacked underneath each other. So I'm using the buttons for "anchor-scrolling" and want to make them show vise versa, when my scroll position is over a specific position. Here is my code:

<ion-segment [(ngModel)]="segData">
  <ion-segment-button (click)="this.scrollToCard('card1')" value="seg1">Card1</ion-segment-button>
  <ion-segment-button (click)="this.scrollToCard('card2')" value="seg2">Card2</ion-segment-button>
</ion-segment>

<div [ngSwitch]="segData">
  <ion-list *ngSwitchCase="'seg1'">
    <ion-item>
      <ion-card #card1>...</ion-card>
    </ion-item>
    <ion-item>
      <ion-card #card2>...</ion-card>
    </ion-item>
  </ion-list>
</div>

example.ts

segData: string;

export class ShowCar
  {
  @ViewChild(Content) content : Content;
  ...
  constructor(...)
    {
    this.segData = "seg1";
    }
  ...
  ionViewDidLoad()
    {  
    //This would work
    //setTimeout( () => { this.segData = "seg2"; }

    //Inside ionScroll.subscribe() it is not working
    //Even if i wrap this into "setTimeout"
    this.content.ionScroll.subscribe( scrollData =>
      {
      if( scrollData.scrollTop > seg1PosFromTop)
        this.segData = "seg2";
      });
    }
  ...
  }

I tried a lot of things and some crazy stuff might be going on. For example, since latest angular allows to work with elements directly from the DOM, I triggered an click-event on the element. The segment then shortly appears to be active and after a millisecond, the previous segment turned active again. Also I was playing around with just changing css classes. However when clicking on the segment-buttons I had to capture that, remove all segment-button segment-active classes and adding it manually to the chosen one.


Solution

  • Okay, since nobody answered my question, I spent a lot of time trying and researching. Here we go, the solution:

    Every scroll movement in an ionic app happens to be outside of angular for performance reasons. So one can not do modification of angular variables or do a content.resize() inside of any scroll event handler (ionScroll, ionScrollStart, ionScrollEnd).

    So you have to wrap every code into: this.zone.run()

    import { Component, NgZone } from '@angular/core';
    @Component({
      template: `
        <ion-header>
          <ion-navbar>
            <ion-title></ion-title>
          </ion-navbar>
        </ion-header>
        <ion-content (ionScroll)="scrollHandler($event)">
           <p> Some realllllllly long content </p>
        </ion-content>
    `})
    class E2EPage {
     public scrollAmount = 0;
     constructor( public zone: NgZone){}
     scrollHandler(event) {
       console.log(`ScrollEvent: ${event}`)
       this.zone.run(()=>{
         // since scrollAmount is data-binded,
         // the update needs to happen in zone
         this.scrollAmount++
       })
     }
    }
    

    https://ionicframework.com/docs/api/components/content/Content/#advanced