Angular Rxjs Observable Chain with ngrx store












1















I am using Angular 7 with ngrx store. The store contains app state, which I am subscribing to in app components on the OnInit. There are couple of variables in store, which are interchangeable (swapped with a button).



Here is my example code in a component.



this.appState.getGasStationSushi().pipe(switchMap((sushi) => {
this.gsSushi = sushi;
return this.appState.getStarbucksSushi();
}), switchMap((sushi) => {
this.sbSushi = sushi;
return this.service.compare(this.gsSushi, this.sbSushi);
}).subscribe((result)=>{
console.log(result);
}));


With a button click in view, user can change both sushi values, which is causing the last subscription call twice, which makes sense (RxJS). I could remove switchMap and write something like



-- gas station sushi susbcription 
-- star bucks sushi susbcription
-- compare


I am not really huge fan of this, I am sure there must be a rxjs/operator of sort. Could someone please make a suggestion?



Also, tried forkjoin, but with ngrx store it seems like, one need to call first or last something like below. Here is a reference for the above statement forkjoinWithstore



const $sushiObs = [
this.appState.getGasStationSushi().pipe(first()),
this.appState.getStarbucksSushi().pipe(first())
];
forkjoin($sushiObs).subscribe((result) => {
console.log(result);
});


If I use the above pattern, the subscriptions fire for the first time but not after that at all.










share|improve this question




















  • 2





    getGasStationSushi. I would never eat Sushi from a gas station.

    – cgTag
    Dec 28 '18 at 20:12
















1















I am using Angular 7 with ngrx store. The store contains app state, which I am subscribing to in app components on the OnInit. There are couple of variables in store, which are interchangeable (swapped with a button).



Here is my example code in a component.



this.appState.getGasStationSushi().pipe(switchMap((sushi) => {
this.gsSushi = sushi;
return this.appState.getStarbucksSushi();
}), switchMap((sushi) => {
this.sbSushi = sushi;
return this.service.compare(this.gsSushi, this.sbSushi);
}).subscribe((result)=>{
console.log(result);
}));


With a button click in view, user can change both sushi values, which is causing the last subscription call twice, which makes sense (RxJS). I could remove switchMap and write something like



-- gas station sushi susbcription 
-- star bucks sushi susbcription
-- compare


I am not really huge fan of this, I am sure there must be a rxjs/operator of sort. Could someone please make a suggestion?



Also, tried forkjoin, but with ngrx store it seems like, one need to call first or last something like below. Here is a reference for the above statement forkjoinWithstore



const $sushiObs = [
this.appState.getGasStationSushi().pipe(first()),
this.appState.getStarbucksSushi().pipe(first())
];
forkjoin($sushiObs).subscribe((result) => {
console.log(result);
});


If I use the above pattern, the subscriptions fire for the first time but not after that at all.










share|improve this question




















  • 2





    getGasStationSushi. I would never eat Sushi from a gas station.

    – cgTag
    Dec 28 '18 at 20:12














1












1








1








I am using Angular 7 with ngrx store. The store contains app state, which I am subscribing to in app components on the OnInit. There are couple of variables in store, which are interchangeable (swapped with a button).



Here is my example code in a component.



this.appState.getGasStationSushi().pipe(switchMap((sushi) => {
this.gsSushi = sushi;
return this.appState.getStarbucksSushi();
}), switchMap((sushi) => {
this.sbSushi = sushi;
return this.service.compare(this.gsSushi, this.sbSushi);
}).subscribe((result)=>{
console.log(result);
}));


With a button click in view, user can change both sushi values, which is causing the last subscription call twice, which makes sense (RxJS). I could remove switchMap and write something like



-- gas station sushi susbcription 
-- star bucks sushi susbcription
-- compare


I am not really huge fan of this, I am sure there must be a rxjs/operator of sort. Could someone please make a suggestion?



Also, tried forkjoin, but with ngrx store it seems like, one need to call first or last something like below. Here is a reference for the above statement forkjoinWithstore



const $sushiObs = [
this.appState.getGasStationSushi().pipe(first()),
this.appState.getStarbucksSushi().pipe(first())
];
forkjoin($sushiObs).subscribe((result) => {
console.log(result);
});


If I use the above pattern, the subscriptions fire for the first time but not after that at all.










share|improve this question
















I am using Angular 7 with ngrx store. The store contains app state, which I am subscribing to in app components on the OnInit. There are couple of variables in store, which are interchangeable (swapped with a button).



Here is my example code in a component.



this.appState.getGasStationSushi().pipe(switchMap((sushi) => {
this.gsSushi = sushi;
return this.appState.getStarbucksSushi();
}), switchMap((sushi) => {
this.sbSushi = sushi;
return this.service.compare(this.gsSushi, this.sbSushi);
}).subscribe((result)=>{
console.log(result);
}));


With a button click in view, user can change both sushi values, which is causing the last subscription call twice, which makes sense (RxJS). I could remove switchMap and write something like



-- gas station sushi susbcription 
-- star bucks sushi susbcription
-- compare


I am not really huge fan of this, I am sure there must be a rxjs/operator of sort. Could someone please make a suggestion?



Also, tried forkjoin, but with ngrx store it seems like, one need to call first or last something like below. Here is a reference for the above statement forkjoinWithstore



const $sushiObs = [
this.appState.getGasStationSushi().pipe(first()),
this.appState.getStarbucksSushi().pipe(first())
];
forkjoin($sushiObs).subscribe((result) => {
console.log(result);
});


If I use the above pattern, the subscriptions fire for the first time but not after that at all.







angular typescript rxjs






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 28 '18 at 19:53







Aj1

















asked Dec 28 '18 at 19:42









Aj1Aj1

4131827




4131827








  • 2





    getGasStationSushi. I would never eat Sushi from a gas station.

    – cgTag
    Dec 28 '18 at 20:12














  • 2





    getGasStationSushi. I would never eat Sushi from a gas station.

    – cgTag
    Dec 28 '18 at 20:12








2




2





getGasStationSushi. I would never eat Sushi from a gas station.

– cgTag
Dec 28 '18 at 20:12





getGasStationSushi. I would never eat Sushi from a gas station.

– cgTag
Dec 28 '18 at 20:12












1 Answer
1






active

oldest

votes


















1














First of all, here is a working example on stackblitz.



Instead of using a store I just created a mock class SushiState that returns observables.



class SushiState {
private _gas = new BehaviorSubject(1);
private _starbucks = new BehaviorSubject(1);

public get gas() {
return this._gas.asObservable();
}
public get starbucks() {
return this._gas.asObservable();
}

public increaseSushi(n = 1) {
this._gas.next(this._gas.value + n);
this._starbucks.next(this._starbucks.value + n);
}

public static compareSushi(g: number, s: number): string {
return `gas is ${g}, starbucks is ${s}`;
}
}


As for the component, here is the code.



export class AppComponent implements OnInit {
state: SushiState;

gasSushi: Observable<number>;
sbSushi: Observable<number>;

combined: string;
combinedTimes = 0;
zipped: string;
zippedTimes = 0;

ngOnInit() {
this.state = new SushiState;
this.gasSushi = this.state.gas;
this.sbSushi = this.state.gas;

const combined = combineLatest(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('combined', sushi);
this.combinedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
combined.subscribe(result => this.combined = result);

const zipped = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('zipped', sushi);
this.zippedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
zipped.subscribe(result => this.zipped = result);
}

increaseSushi() {
this.state.increaseSushi();
}

}


If you run it on stackblitz and check the console, you will see the following behaviour:



console output



If we use combined latest, we combine the observables separately and only care about the latest state, resulting in 2 calls of console.log.



We could instead use zip, which waits for both observables to emit, before producing an output. This looks like the perfect fit for our "Increase Both" button, but there's a problem: if the starbucksSushi get incremented separately (maybe from a different part of the app), the zipped version will wait for the gas station sushi to get updated too.



To suggest a third solution, you could use combineLatest to combine the sushi counters, and then use debounceTime operator to wait for some number of milliseconds before emitting the output.



const debounced = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('debounced', sushi);
this.debouncedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
debounceTime(100),
);
debounced.subscribe(result => this.debounced = result);


This will react to changes in all the sources, but not more often than 100ms.



Finally, the reason why you had to do first():



forkJoin joins the observables after they complete (which can happen only once, so it's not a good fit for a continuous stream) and is more suitable for "promise-like" work, e.g. HTTP calls, process completions, etc. Incidentally, if you only take one element from a stream, the resulting stream completes after the single emission.



P.S.



I recommend utilizing the async pipe for working with observables (like i've done with the properties



gasSushi: Observable<number>;
sbSushi: Observable<number>;


and inside the template then



<div>
<h3>starbucks sushi</h3>
<p>{{sbSushi | async}}</p>
</div>


instead of



result => this.zipped = result


I have used both in this example so you can compare them. From my experience, working with observables gets much easier, once you stop converting "de-observing" them ahead of time and just allow the async pipe to do its work.



On top of that, if you use subscribe somewhere in your component, you should unsubscribe when the component is destroyed - which is not hard at all, but if we never subscribe explicitly, and allow the async pipe to do the subscription, it also handles the destruction for us :)






share|improve this answer


























  • This is neat!!!

    – KiraAG
    Dec 29 '18 at 8:07











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53963571%2fangular-rxjs-observable-chain-with-ngrx-store%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














First of all, here is a working example on stackblitz.



Instead of using a store I just created a mock class SushiState that returns observables.



class SushiState {
private _gas = new BehaviorSubject(1);
private _starbucks = new BehaviorSubject(1);

public get gas() {
return this._gas.asObservable();
}
public get starbucks() {
return this._gas.asObservable();
}

public increaseSushi(n = 1) {
this._gas.next(this._gas.value + n);
this._starbucks.next(this._starbucks.value + n);
}

public static compareSushi(g: number, s: number): string {
return `gas is ${g}, starbucks is ${s}`;
}
}


As for the component, here is the code.



export class AppComponent implements OnInit {
state: SushiState;

gasSushi: Observable<number>;
sbSushi: Observable<number>;

combined: string;
combinedTimes = 0;
zipped: string;
zippedTimes = 0;

ngOnInit() {
this.state = new SushiState;
this.gasSushi = this.state.gas;
this.sbSushi = this.state.gas;

const combined = combineLatest(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('combined', sushi);
this.combinedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
combined.subscribe(result => this.combined = result);

const zipped = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('zipped', sushi);
this.zippedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
zipped.subscribe(result => this.zipped = result);
}

increaseSushi() {
this.state.increaseSushi();
}

}


If you run it on stackblitz and check the console, you will see the following behaviour:



console output



If we use combined latest, we combine the observables separately and only care about the latest state, resulting in 2 calls of console.log.



We could instead use zip, which waits for both observables to emit, before producing an output. This looks like the perfect fit for our "Increase Both" button, but there's a problem: if the starbucksSushi get incremented separately (maybe from a different part of the app), the zipped version will wait for the gas station sushi to get updated too.



To suggest a third solution, you could use combineLatest to combine the sushi counters, and then use debounceTime operator to wait for some number of milliseconds before emitting the output.



const debounced = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('debounced', sushi);
this.debouncedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
debounceTime(100),
);
debounced.subscribe(result => this.debounced = result);


This will react to changes in all the sources, but not more often than 100ms.



Finally, the reason why you had to do first():



forkJoin joins the observables after they complete (which can happen only once, so it's not a good fit for a continuous stream) and is more suitable for "promise-like" work, e.g. HTTP calls, process completions, etc. Incidentally, if you only take one element from a stream, the resulting stream completes after the single emission.



P.S.



I recommend utilizing the async pipe for working with observables (like i've done with the properties



gasSushi: Observable<number>;
sbSushi: Observable<number>;


and inside the template then



<div>
<h3>starbucks sushi</h3>
<p>{{sbSushi | async}}</p>
</div>


instead of



result => this.zipped = result


I have used both in this example so you can compare them. From my experience, working with observables gets much easier, once you stop converting "de-observing" them ahead of time and just allow the async pipe to do its work.



On top of that, if you use subscribe somewhere in your component, you should unsubscribe when the component is destroyed - which is not hard at all, but if we never subscribe explicitly, and allow the async pipe to do the subscription, it also handles the destruction for us :)






share|improve this answer


























  • This is neat!!!

    – KiraAG
    Dec 29 '18 at 8:07
















1














First of all, here is a working example on stackblitz.



Instead of using a store I just created a mock class SushiState that returns observables.



class SushiState {
private _gas = new BehaviorSubject(1);
private _starbucks = new BehaviorSubject(1);

public get gas() {
return this._gas.asObservable();
}
public get starbucks() {
return this._gas.asObservable();
}

public increaseSushi(n = 1) {
this._gas.next(this._gas.value + n);
this._starbucks.next(this._starbucks.value + n);
}

public static compareSushi(g: number, s: number): string {
return `gas is ${g}, starbucks is ${s}`;
}
}


As for the component, here is the code.



export class AppComponent implements OnInit {
state: SushiState;

gasSushi: Observable<number>;
sbSushi: Observable<number>;

combined: string;
combinedTimes = 0;
zipped: string;
zippedTimes = 0;

ngOnInit() {
this.state = new SushiState;
this.gasSushi = this.state.gas;
this.sbSushi = this.state.gas;

const combined = combineLatest(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('combined', sushi);
this.combinedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
combined.subscribe(result => this.combined = result);

const zipped = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('zipped', sushi);
this.zippedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
zipped.subscribe(result => this.zipped = result);
}

increaseSushi() {
this.state.increaseSushi();
}

}


If you run it on stackblitz and check the console, you will see the following behaviour:



console output



If we use combined latest, we combine the observables separately and only care about the latest state, resulting in 2 calls of console.log.



We could instead use zip, which waits for both observables to emit, before producing an output. This looks like the perfect fit for our "Increase Both" button, but there's a problem: if the starbucksSushi get incremented separately (maybe from a different part of the app), the zipped version will wait for the gas station sushi to get updated too.



To suggest a third solution, you could use combineLatest to combine the sushi counters, and then use debounceTime operator to wait for some number of milliseconds before emitting the output.



const debounced = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('debounced', sushi);
this.debouncedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
debounceTime(100),
);
debounced.subscribe(result => this.debounced = result);


This will react to changes in all the sources, but not more often than 100ms.



Finally, the reason why you had to do first():



forkJoin joins the observables after they complete (which can happen only once, so it's not a good fit for a continuous stream) and is more suitable for "promise-like" work, e.g. HTTP calls, process completions, etc. Incidentally, if you only take one element from a stream, the resulting stream completes after the single emission.



P.S.



I recommend utilizing the async pipe for working with observables (like i've done with the properties



gasSushi: Observable<number>;
sbSushi: Observable<number>;


and inside the template then



<div>
<h3>starbucks sushi</h3>
<p>{{sbSushi | async}}</p>
</div>


instead of



result => this.zipped = result


I have used both in this example so you can compare them. From my experience, working with observables gets much easier, once you stop converting "de-observing" them ahead of time and just allow the async pipe to do its work.



On top of that, if you use subscribe somewhere in your component, you should unsubscribe when the component is destroyed - which is not hard at all, but if we never subscribe explicitly, and allow the async pipe to do the subscription, it also handles the destruction for us :)






share|improve this answer


























  • This is neat!!!

    – KiraAG
    Dec 29 '18 at 8:07














1












1








1







First of all, here is a working example on stackblitz.



Instead of using a store I just created a mock class SushiState that returns observables.



class SushiState {
private _gas = new BehaviorSubject(1);
private _starbucks = new BehaviorSubject(1);

public get gas() {
return this._gas.asObservable();
}
public get starbucks() {
return this._gas.asObservable();
}

public increaseSushi(n = 1) {
this._gas.next(this._gas.value + n);
this._starbucks.next(this._starbucks.value + n);
}

public static compareSushi(g: number, s: number): string {
return `gas is ${g}, starbucks is ${s}`;
}
}


As for the component, here is the code.



export class AppComponent implements OnInit {
state: SushiState;

gasSushi: Observable<number>;
sbSushi: Observable<number>;

combined: string;
combinedTimes = 0;
zipped: string;
zippedTimes = 0;

ngOnInit() {
this.state = new SushiState;
this.gasSushi = this.state.gas;
this.sbSushi = this.state.gas;

const combined = combineLatest(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('combined', sushi);
this.combinedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
combined.subscribe(result => this.combined = result);

const zipped = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('zipped', sushi);
this.zippedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
zipped.subscribe(result => this.zipped = result);
}

increaseSushi() {
this.state.increaseSushi();
}

}


If you run it on stackblitz and check the console, you will see the following behaviour:



console output



If we use combined latest, we combine the observables separately and only care about the latest state, resulting in 2 calls of console.log.



We could instead use zip, which waits for both observables to emit, before producing an output. This looks like the perfect fit for our "Increase Both" button, but there's a problem: if the starbucksSushi get incremented separately (maybe from a different part of the app), the zipped version will wait for the gas station sushi to get updated too.



To suggest a third solution, you could use combineLatest to combine the sushi counters, and then use debounceTime operator to wait for some number of milliseconds before emitting the output.



const debounced = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('debounced', sushi);
this.debouncedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
debounceTime(100),
);
debounced.subscribe(result => this.debounced = result);


This will react to changes in all the sources, but not more often than 100ms.



Finally, the reason why you had to do first():



forkJoin joins the observables after they complete (which can happen only once, so it's not a good fit for a continuous stream) and is more suitable for "promise-like" work, e.g. HTTP calls, process completions, etc. Incidentally, if you only take one element from a stream, the resulting stream completes after the single emission.



P.S.



I recommend utilizing the async pipe for working with observables (like i've done with the properties



gasSushi: Observable<number>;
sbSushi: Observable<number>;


and inside the template then



<div>
<h3>starbucks sushi</h3>
<p>{{sbSushi | async}}</p>
</div>


instead of



result => this.zipped = result


I have used both in this example so you can compare them. From my experience, working with observables gets much easier, once you stop converting "de-observing" them ahead of time and just allow the async pipe to do its work.



On top of that, if you use subscribe somewhere in your component, you should unsubscribe when the component is destroyed - which is not hard at all, but if we never subscribe explicitly, and allow the async pipe to do the subscription, it also handles the destruction for us :)






share|improve this answer















First of all, here is a working example on stackblitz.



Instead of using a store I just created a mock class SushiState that returns observables.



class SushiState {
private _gas = new BehaviorSubject(1);
private _starbucks = new BehaviorSubject(1);

public get gas() {
return this._gas.asObservable();
}
public get starbucks() {
return this._gas.asObservable();
}

public increaseSushi(n = 1) {
this._gas.next(this._gas.value + n);
this._starbucks.next(this._starbucks.value + n);
}

public static compareSushi(g: number, s: number): string {
return `gas is ${g}, starbucks is ${s}`;
}
}


As for the component, here is the code.



export class AppComponent implements OnInit {
state: SushiState;

gasSushi: Observable<number>;
sbSushi: Observable<number>;

combined: string;
combinedTimes = 0;
zipped: string;
zippedTimes = 0;

ngOnInit() {
this.state = new SushiState;
this.gasSushi = this.state.gas;
this.sbSushi = this.state.gas;

const combined = combineLatest(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('combined', sushi);
this.combinedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
combined.subscribe(result => this.combined = result);

const zipped = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('zipped', sushi);
this.zippedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
);
zipped.subscribe(result => this.zipped = result);
}

increaseSushi() {
this.state.increaseSushi();
}

}


If you run it on stackblitz and check the console, you will see the following behaviour:



console output



If we use combined latest, we combine the observables separately and only care about the latest state, resulting in 2 calls of console.log.



We could instead use zip, which waits for both observables to emit, before producing an output. This looks like the perfect fit for our "Increase Both" button, but there's a problem: if the starbucksSushi get incremented separately (maybe from a different part of the app), the zipped version will wait for the gas station sushi to get updated too.



To suggest a third solution, you could use combineLatest to combine the sushi counters, and then use debounceTime operator to wait for some number of milliseconds before emitting the output.



const debounced = zip(
this.gasSushi,
this.sbSushi,
).pipe(
tap((sushi) => {
console.log('debounced', sushi);
this.debouncedTimes++;
}),
map((sushi) => SushiState.compareSushi(sushi[0], sushi[1])),
debounceTime(100),
);
debounced.subscribe(result => this.debounced = result);


This will react to changes in all the sources, but not more often than 100ms.



Finally, the reason why you had to do first():



forkJoin joins the observables after they complete (which can happen only once, so it's not a good fit for a continuous stream) and is more suitable for "promise-like" work, e.g. HTTP calls, process completions, etc. Incidentally, if you only take one element from a stream, the resulting stream completes after the single emission.



P.S.



I recommend utilizing the async pipe for working with observables (like i've done with the properties



gasSushi: Observable<number>;
sbSushi: Observable<number>;


and inside the template then



<div>
<h3>starbucks sushi</h3>
<p>{{sbSushi | async}}</p>
</div>


instead of



result => this.zipped = result


I have used both in this example so you can compare them. From my experience, working with observables gets much easier, once you stop converting "de-observing" them ahead of time and just allow the async pipe to do its work.



On top of that, if you use subscribe somewhere in your component, you should unsubscribe when the component is destroyed - which is not hard at all, but if we never subscribe explicitly, and allow the async pipe to do the subscription, it also handles the destruction for us :)







share|improve this answer














share|improve this answer



share|improve this answer








edited Dec 28 '18 at 21:00

























answered Dec 28 '18 at 20:46









hlfrmnhlfrmn

1,0221121




1,0221121













  • This is neat!!!

    – KiraAG
    Dec 29 '18 at 8:07



















  • This is neat!!!

    – KiraAG
    Dec 29 '18 at 8:07

















This is neat!!!

– KiraAG
Dec 29 '18 at 8:07





This is neat!!!

– KiraAG
Dec 29 '18 at 8:07


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53963571%2fangular-rxjs-observable-chain-with-ngrx-store%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Angular Downloading a file using contenturl with Basic Authentication

Olmecas

Can't read property showImagePicker of undefined in react native iOS