MOBILE-3947 swipe: Fix Swipe slides update component
parent
210b3a75a3
commit
522d1e2c79
|
@ -142,7 +142,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component loaded.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.canNavigate = typeof this.canNavigate == 'undefined' ? true : CoreUtils.isTrueOrOne(this.canNavigate);
|
this.canNavigate = typeof this.canNavigate == 'undefined' ? true : CoreUtils.isTrueOrOne(this.canNavigate);
|
||||||
|
@ -164,7 +164,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect and act upon changes that Angular can’t or won’t detect on its own (objects and arrays).
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngDoCheck(): void {
|
ngDoCheck(): void {
|
||||||
const items = this.manager?.getSource().getItems();
|
const items = this.manager?.getSource().getItems();
|
||||||
|
@ -368,7 +368,7 @@ export class AddonCalendarCalendarComponent implements OnInit, DoCheck, OnDestro
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component destroyed.
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.undeleteEventObserver?.off();
|
this.undeleteEventObserver?.off();
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
import {
|
import {
|
||||||
Component, ContentChild, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChange, TemplateRef, ViewChild,
|
Component, ContentChild, ElementRef, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChange, TemplateRef, ViewChild,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
|
import { AsyncDirective } from '@classes/async-directive';
|
||||||
import { CoreSwipeSlidesItemsManager } from '@classes/items-management/swipe-slides-items-manager';
|
import { CoreSwipeSlidesItemsManager } from '@classes/items-management/swipe-slides-items-manager';
|
||||||
|
import { CorePromisedValue } from '@classes/promised-value';
|
||||||
import { IonContent } from '@ionic/angular';
|
import { IonContent } from '@ionic/angular';
|
||||||
import { CoreDomUtils, VerticalPoint } from '@services/utils/dom';
|
import { CoreDomUtils, VerticalPoint } from '@services/utils/dom';
|
||||||
import { CoreUtils } from '@services/utils/utils';
|
import { CoreUtils } from '@services/utils/utils';
|
||||||
|
@ -32,7 +34,7 @@ import { SwiperOptions } from 'swiper/types';
|
||||||
templateUrl: 'swipe-slides.html',
|
templateUrl: 'swipe-slides.html',
|
||||||
styleUrls: ['swipe-slides.scss'],
|
styleUrls: ['swipe-slides.scss'],
|
||||||
})
|
})
|
||||||
export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDestroy {
|
export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDestroy, AsyncDirective {
|
||||||
|
|
||||||
@Input() manager?: CoreSwipeSlidesItemsManager<Item>;
|
@Input() manager?: CoreSwipeSlidesItemsManager<Item>;
|
||||||
@Input() options: CoreSwipeSlidesOptions = {};
|
@Input() options: CoreSwipeSlidesOptions = {};
|
||||||
|
@ -46,22 +48,21 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
* This setTimeout waits for Ionic's async initialization to complete.
|
* This setTimeout waits for Ionic's async initialization to complete.
|
||||||
* Otherwise, an outdated swiper reference will be used.
|
* Otherwise, an outdated swiper reference will be used.
|
||||||
*/
|
*/
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
if (swiperRef?.nativeElement?.swiper) {
|
if (swiperRef?.nativeElement?.swiper) {
|
||||||
this.swiper = swiperRef.nativeElement.swiper as Swiper;
|
this.swiper = swiperRef.nativeElement.swiper as Swiper;
|
||||||
|
|
||||||
|
await this.initialize();
|
||||||
|
|
||||||
if (this.options.initialSlide) {
|
if (this.options.initialSlide) {
|
||||||
this.swiper.slideTo(this.options.initialSlide, 0, this.options.runCallbacksOnInit);
|
this.swiper.slideTo(this.options.initialSlide, 0, this.options.runCallbacksOnInit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateOptions();
|
||||||
|
|
||||||
this.swiper.on('slideChangeTransitionStart', () => this.slideWillChange());
|
this.swiper.on('slideChangeTransitionStart', () => this.slideWillChange());
|
||||||
this.swiper.on('slideChangeTransitionEnd', () => this.slideDidChange());
|
this.swiper.on('slideChangeTransitionEnd', () => this.slideDidChange());
|
||||||
|
|
||||||
Object.keys(this.options).forEach((key) => {
|
|
||||||
if (this.swiper) {
|
|
||||||
this.swiper.params[key] = this.options[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
@ -72,6 +73,7 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
protected unsubscribe?: () => void;
|
protected unsubscribe?: () => void;
|
||||||
protected resizeListener: CoreEventObserver;
|
protected resizeListener: CoreEventObserver;
|
||||||
protected activeSlideIndexes: number[] = [];
|
protected activeSlideIndexes: number[] = [];
|
||||||
|
protected onReadyPromise = new CorePromisedValue<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
elementRef: ElementRef<HTMLElement>,
|
elementRef: ElementRef<HTMLElement>,
|
||||||
|
@ -87,17 +89,11 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
*/
|
*/
|
||||||
ngOnChanges(changes: { [name: string]: SimpleChange }): void {
|
async ngOnChanges(changes: { [name: string]: SimpleChange }): Promise<void> {
|
||||||
if (!this.unsubscribe && this.manager) {
|
await this.initialize();
|
||||||
this.initialize(this.manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (changes.options) {
|
if (changes.options) {
|
||||||
Object.keys(this.options).forEach((key) => {
|
this.updateOptions();
|
||||||
if (this.swiper) {
|
|
||||||
this.swiper.params[key] = this.options[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +118,12 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
/**
|
/**
|
||||||
* Initialize some properties based on the manager.
|
* Initialize some properties based on the manager.
|
||||||
*/
|
*/
|
||||||
protected async initialize(manager: CoreSwipeSlidesItemsManager<Item>): Promise<void> {
|
protected async initialize(): Promise<void> {
|
||||||
this.unsubscribe = manager.getSource().addListener({
|
if (this.unsubscribe || !this.swiper || !this.manager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.unsubscribe = this.manager.getSource().addListener({
|
||||||
onItemsUpdated: () => this.onItemsUpdated(),
|
onItemsUpdated: () => this.onItemsUpdated(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -131,16 +131,16 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
// This is because default callbacks aren't triggered for index 0, and to prevent auto scroll on init.
|
// This is because default callbacks aren't triggered for index 0, and to prevent auto scroll on init.
|
||||||
this.options.runCallbacksOnInit = false;
|
this.options.runCallbacksOnInit = false;
|
||||||
|
|
||||||
await manager.getSource().waitForLoaded();
|
await this.manager.getSource().waitForLoaded();
|
||||||
|
|
||||||
if (this.options.initialSlide === undefined) {
|
if (this.options.initialSlide === undefined) {
|
||||||
// Calculate the initial slide.
|
// Calculate the initial slide.
|
||||||
const index = manager.getSource().getInitialItemIndex();
|
const index = this.manager.getSource().getInitialItemIndex();
|
||||||
this.options.initialSlide = Math.max(index, 0);
|
this.options.initialSlide = Math.max(index, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit change events with the initial item.
|
// Emit change events with the initial item.
|
||||||
const items = manager.getSource().getItems();
|
const items = this.manager.getSource().getItems();
|
||||||
if (!items || !items.length) {
|
if (!items || !items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -155,9 +155,11 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
|
|
||||||
this.activeSlideIndexes = [initialIndex];
|
this.activeSlideIndexes = [initialIndex];
|
||||||
|
|
||||||
manager.setSelectedItem(items[initialIndex]);
|
this.manager.setSelectedItem(items[initialIndex]);
|
||||||
this.onWillChange.emit(initialItemData);
|
this.onWillChange.emit(initialItemData);
|
||||||
this.onDidChange.emit(initialItemData);
|
this.onDidChange.emit(initialItemData);
|
||||||
|
|
||||||
|
this.onReadyPromise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,19 +169,20 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
* @param speed Animation speed.
|
* @param speed Animation speed.
|
||||||
* @param runCallbacks Whether to run callbacks.
|
* @param runCallbacks Whether to run callbacks.
|
||||||
*/
|
*/
|
||||||
slideToIndex(index: number, speed?: number, runCallbacks?: boolean): void {
|
async slideToIndex(index: number, speed?: number, runCallbacks?: boolean): Promise<void> {
|
||||||
// If slides are being updated, wait for the update to finish.
|
// If slides are being updated, wait for the update to finish.
|
||||||
if (!this.swiper) {
|
await this.ready();
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the number of slides matches the number of items.
|
// Verify that the number of slides matches the number of items.
|
||||||
const slidesLength = this.swiper.slides.length;
|
const slidesLength = this.swiper?.slides?.length || 0;
|
||||||
if (slidesLength !== this.items.length) {
|
if (slidesLength !== this.items.length) {
|
||||||
// Number doesn't match, do a new update to try to match them.
|
// Number doesn't match, do a new update to try to match them.
|
||||||
this.updateSlidesComponent();
|
await this.updateSlidesComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.swiper?.slides) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.swiper?.slideTo(index, speed, runCallbacks);
|
this.swiper?.slideTo(index, speed, runCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,10 +193,10 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
* @param speed Animation speed.
|
* @param speed Animation speed.
|
||||||
* @param runCallbacks Whether to run callbacks.
|
* @param runCallbacks Whether to run callbacks.
|
||||||
*/
|
*/
|
||||||
slideToItem(item: Item, speed?: number, runCallbacks?: boolean): void {
|
async slideToItem(item: Item, speed?: number, runCallbacks?: boolean): Promise<void> {
|
||||||
const index = this.manager?.getSource().getItemIndex(item) ?? -1;
|
const index = this.manager?.getSource().getItemIndex(item) ?? -1;
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
this.slideToIndex(index, speed, runCallbacks);
|
await this.slideToIndex(index, speed, runCallbacks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +228,7 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
await CoreUtils.nextTick();
|
await CoreUtils.nextTick();
|
||||||
|
|
||||||
// Update the slides component so the slides list reflects the new items.
|
// Update the slides component so the slides list reflects the new items.
|
||||||
this.updateSlidesComponent();
|
await this.updateSlidesComponent();
|
||||||
|
|
||||||
const currentItem = this.manager?.getSelectedItem();
|
const currentItem = this.manager?.getSelectedItem();
|
||||||
|
|
||||||
|
@ -234,10 +237,26 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the same slide in case the list has changed.
|
// Keep the same slide in case the list has changed.
|
||||||
const newIndex = this.manager.getSource().getItemIndex(currentItem) ?? -1;
|
this.slideToItem(currentItem, 0, false);
|
||||||
if (newIndex != -1) {
|
|
||||||
this.swiper?.slideTo(newIndex, 0, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Swiper params from options.
|
||||||
|
*/
|
||||||
|
protected updateOptions(): void {
|
||||||
|
if (!this.swiper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.swiper.params === undefined) {
|
||||||
|
this.swiper.params = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(this.options).forEach((key) => {
|
||||||
|
if (this.swiper) {
|
||||||
|
this.swiper.params[key] = this.options[key];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,8 +341,24 @@ export class CoreSwipeSlidesComponent<Item = unknown> implements OnChanges, OnDe
|
||||||
/**
|
/**
|
||||||
* Update slides component.
|
* Update slides component.
|
||||||
*/
|
*/
|
||||||
updateSlidesComponent(): void {
|
async updateSlidesComponent(): Promise<void> {
|
||||||
|
await this.ready();
|
||||||
|
|
||||||
|
if (!this.swiper) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.swiper?.update();
|
this.swiper?.update();
|
||||||
|
|
||||||
|
// We need to ensure the slides are updated before continuing.
|
||||||
|
await CoreUtils.nextTicks(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritdoc
|
||||||
|
*/
|
||||||
|
async ready(): Promise<void> {
|
||||||
|
return this.onReadyPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue