Ionic v3 Segment - Change active segment while scrolling

3.1k Views Asked by At

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.

2

There are 2 best solutions below

0
On BEST ANSWER

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

0
On

Here is the complete solution with ionic4:

// tab.page.html

<ion-header  >
 <!-- Scrollable Segment -->
 <ion-toolbar class="less-height" color="primary">
    <ion-segment scrollable mode="md" (ionChange)="segmentChanged(segment)" [(ngModel)]="segment" >
        <ion-segment-button mode="md" id="seg-1" value="0">
          <p>Description</p>
        </ion-segment-button>
        <ion-segment-button mode="md" id="seg-2" value="1">
          <p>Interconnections</p>
        </ion-segment-button>
        <ion-segment-button mode="md" id="seg-3" value="2">
          <p>Declensions</p>
        </ion-segment-button>
        <ion-segment-button mode="md" id="seg-4" value="3">
          <p>Phraseologisms</p>
        </ion-segment-button>
        <ion-segment-button mode="md" id="seg-5" value="4">
          <p>Etymology</p>
        </ion-segment-button>
        <ion-segment-button mode="md" id="seg-6" value="5">
          <p>Analysis</p>
        </ion-segment-button>
      </ion-segment>
</ion-toolbar>
</ion-header>

<ion-content>
    <ion-slides (ionSlideDidChange)="slideChanged()" class="word-slides">
        <ion-slide>
          <p>Slide 1</p>
        </ion-slide>
        <ion-slide>
          <p>Slide 2</p>
        </ion-slide>
        <ion-slide>
          <p>Slide 3</p>
        </ion-slide>
        <ion-slide>
          <p>Slide 4</p>
        </ion-slide>
        <ion-slide>
          <p>Slide 5</p>
        </ion-slide>
        <ion-slide>
          <p>Slide 6</p>
        </ion-slide>
      </ion-slides>
</ion-content>

// tab.page.ts

 @ViewChild(IonSlides) slider: IonSlides;
  segment = 0;
  constructor() {}
async segmentChanged(event) {
  await this.slider.slideTo(this.segment);
  this.slider.update();
}
async slideChanged() {
  this.segment = await this.slider.getActiveIndex();
  this.focusSegment(this.segment+1);
}

focusSegment(segmentId) {
  document.getElementById('seg-'+segmentId).scrollIntoView({ 
    behavior: 'smooth',
    block: 'center',
    inline: 'center'
  });
}