pull-to-refresh functionality is working in the Angular web application, but when deployed as a Cordova application, it fails to function as intended.
Upon transitioning our Angular web application into a Cordova application for deployment on mobile platforms, we encountered a notable deviation in behavior. Despite implementing the same pull-to-refresh logic, the feature does not respond as expected when running the application on mobile devices.
this is my code
<div (mousedown)="onTouchStart($event)" (touchstart)="onTouchStart($event)"
(mousemove)="onTouchMove($event)" (touchmove)="onTouchMove($event)"
(mouseup)="onTouchEnd()" (touchend)="onTouchEnd()">
<app-pull-to-refresh></app-pull-to-refresh>
<!-- Your content here (e.g., a list of items) -->
<ul>
<li *ngFor="let item of items">{{ item.name }}</li>
</ul>
</div>
app.component.ts
onTouchStart(event: MouseEvent | TouchEvent) {
// Capture the starting point of the touch/mouse event
// You can customize the threshold to trigger the refresh
if (event instanceof MouseEvent || (event instanceof TouchEvent && event.touches.length === 1)) {
this.showPullToRefresh = true;
this.pullText = 'Release to refresh';
}
}
onTouchMove(event: MouseEvent | TouchEvent) {
// Calculate the distance and determine whether to show the pull-to-refresh indicator
if (event instanceof MouseEvent || (event instanceof TouchEvent && event.touches.length === 1)) {
const startY = event instanceof MouseEvent ? event.clientY : event.touches[0].clientY;
const distanceY = startY - (event instanceof MouseEvent ? this.startY : this.touchStartY);
if (distanceY >= 60) { // Adjust this threshold as needed
this.showPullToRefresh = true;
this.pullText = 'Release to refresh';
} else {
this.showPullToRefresh = false;
this.pullText = 'Pull to refresh';
}
}
}
onTouchEnd() {
if (this.showPullToRefresh) {
// Perform data refresh here
this.refreshData();
this.showPullToRefresh = false;
this.pullText = 'Pull to refresh';
}
}
pull-to-refresh.component.html
<div style="position: absolute; top: 0; left: 50%">
<div
style="margin-left: -35px"
[style.transform]="positionTranslate3d$ | async"
>
<svg
width="70px"
height="70"
[style.transform]="rotateTransform$ | async"
[style.opacity]="opacity$ | async"
>
<!-- via: https://gist.github.com/redblobgames/6851dc787241e390c241cd9484b16e4d -->
<filter id="dropShadow" height="130%">
<feGaussianBlur in="SourceAlpha" stdDeviation="3" />
<feOffset dx="2" dy="2" result="offsetblur" />
<feComponentTransfer>
<feFuncA type="linear" slope="0.5" />
</feComponentTransfer>
<feMerge>
<feMergeNode />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<circle
cy="35"
cx="35"
r="30"
fill="white"
style="filter:url(#dropShadow)"
></circle>
<!-- via: https://material.io/resources/icons/?style=baseline -->
<path
transform="scale(2.0,2.0) translate(5.5,5.5)"
fill="blue"
d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"
/>
</svg>
</div>
</div>
pull-to-refresh.component.ts
import { Component, OnInit } from '@angular/core';
import { concat, defer, fromEvent, Observable, timer } from 'rxjs';
import {
filter,
map,
repeat,
skipUntil,
startWith,
switchMap,
take,
takeUntil,
tap
} from 'rxjs/operators';
import { LoadNotifyService } from 'src/app/services/load-notify.service';
// import { LoadNotifyService } from '../services/load-notify.service';
const TOP_POSITION = 0;
/**
*
*/
@Component({
selector: 'app-pull-to-refresh',
templateUrl: './pull-to-refresh.component.html'
})
export class PullToRefreshComponent implements OnInit {
private readonly pullDistance = window.innerHeight / 3; // 引っ張る距離
private readonly touchstart$ = fromEvent<TouchEvent>(document, 'touchstart');
private readonly touchend$ = fromEvent<TouchEvent>(document, 'touchend');
private readonly touchmove$ = fromEvent<TouchEvent>(document, 'touchmove');
private drag$ = this.touchstart$.pipe(
switchMap(start => {
let pos = TOP_POSITION;
return concat(
this.touchmove$.pipe(
map(move => move.touches[0].pageY - start.touches[0].pageY),
tap(p => (pos = p)),
filter(p => p < this.pullDistance),
takeUntil(this.touchend$)
),
defer(() => this.tweenObservable(pos, TOP_POSITION, 500))
);
}),
repeat()
);
private position$: Observable<number> = this.drag$.pipe(
startWith(TOP_POSITION)
);
positionTranslate3d$: Observable<string> = this.position$.pipe(
map(p => `translate3d(0, ${p - 70}px, 0)`)
);
rotateTransform$: Observable<string> = this.position$.pipe(
map(p => `rotate(${(p / this.pullDistance) * 360}deg)`)
);
opacity$: Observable<number> = this.position$.pipe(
map(p => p / this.pullDistance)
);
constructor(private loadNotifyService: LoadNotifyService) {}
ngOnInit(): void {
this.touchstart$
.pipe(
switchMap(start => {
return this.touchend$.pipe(
map(x => x.changedTouches[0].pageY - start.touches[0].pageY)
);
}),
filter(p => p >= this.pullDistance)
)
.subscribe(() => this.loadNotifyService.notify());
}
private tweenObservable(start:any, end:any, time:any) {
const emissions = time / 10;
const step = (start - end) / emissions;
return timer(0, 10).pipe(
map(x => start - step * (x + 1)),
take(emissions)
);
}
}`
`
Nidhin A G is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.