Reputation: 23
I'm trying limit the emission of subscription:
My object Preferences can change all the time. The API request should run only first time and when x has been changed . I added distinctUntilChanged, but API request fires only on init and when I fire changeY or changeX nothing runs the request, and console.log shows same prev.x and current.x values. When I remove distinctUntilChanged, the api request fires whenever I change changeX () or changeY ()
test.page.ts:
import {Component, OnDestroy, OnInit} from '@angular/core';
import {AuthService} from '../_auth/auth.service';
import {AppService} from '../_app/app.service';
import {User, UserProfileService} from '../../api';
import {Preferences} from '../_interfaces/preferences';
import { Subject} from 'rxjs';
import {tap, takeUntil, switchMap, take, distinctUntilChanged} from 'rxjs/operators';
@Component({
selector: 'app-test',
templateUrl: './test.page.html',
styleUrls: ['./test.page.scss'],
})
export class TestPage implements OnInit, OnDestroy {
public menu: any;
private user: User;
public preferences: Preferences;
private readonly destroy$: Subject<void> = new Subject();
private i = 1;
constructor(public appService: AppService, public authService: AuthService, public userProfile: UserProfileService) {
this.authService.currentUser
.pipe(
take(1),
tap((user: User) => this.user = user),
switchMap(() => this.appService.currentPreferences.pipe(
distinctUntilChanged((prev, current) => {
console.log(prev.x, current.x)
return prev.x === current.x;
}),
tap((preferences: Preferences) => this.preferences = preferences), takeUntil(this.destroy$))),
// fire Api request
switchMap(() => this.userProfile.getMenu(this.user.id, this.preferences.x).pipe(take(1), takeUntil(this.destroy$))),
takeUntil(this.destroy$)
)
.subscribe(res => {
this.menu = res;
alert('Request API done');
});
}
// used in html on button (click)="changeX()"
changeX() {
const copyPreferences: Preferences = this.preferences;
copyPreferences.x = new Date();
this.appService.setPreferences(copyPreferences);
}
// used in html on button (click)="changeY()"
changeY() {
const copyPreferences: Preferences = this.preferences;
copyPreferences.y = new Date();
this.appService.setPreferences(copyPreferences);
}
ngOnInit() {
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
}
preferences.ts:
export interface Preferences {
appToken?: string;
shiftId?: number;
restaurantId?: number;
restaurants?: any;
x?: any;
y?: any;
}
app.service.ts
import {Injectable} from '@angular/core';
import {Storage} from '@ionic/storage';
import {Observable, ReplaySubject} from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AppService {
public currentPreferences: Observable<any>;
public prefernecesState = new ReplaySubject<any>(1);
constructor(private storage: Storage) {
this.currentPreferences = this.prefernecesState.asObservable();
this.setPreferencesState();
}
async setPreferencesState() {
this.storage.get('preferences').then(res => {
if (res) {
this.prefernecesState.next(res);
}
});
}
public setPreferences(preferences) {
this.storage.remove('preferences');
this.storage.set('preferences', preferences);
this.prefernecesState.next(preferences);
}
}
Upvotes: 1
Views: 376
Reputation: 14679
This
const copyPreferences: Preferences = this.preferences;
doesn't actually make a copy, it's just creating another reference to the same object. Any mutation of copyPreferences
is automatically a mutation of this.preferences
. Hence the test prev.x === current.x
will always return true, because prev
and curr
are the same object.
Shallow copying should suffice:
const copyPreferences = Object.assign({}, this.preferences);
Upvotes: 1