Angular Rxjs Observable Chain with ngrx store
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
add a comment |
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
2
getGasStationSushi
. I would never eat Sushi from a gas station.
– cgTag
Dec 28 '18 at 20:12
add a comment |
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
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
angular typescript rxjs
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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:
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 :)
This is neat!!!
– KiraAG
Dec 29 '18 at 8:07
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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:
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 :)
This is neat!!!
– KiraAG
Dec 29 '18 at 8:07
add a comment |
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:
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 :)
This is neat!!!
– KiraAG
Dec 29 '18 at 8:07
add a comment |
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:
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 :)
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:
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 :)
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
2
getGasStationSushi
. I would never eat Sushi from a gas station.– cgTag
Dec 28 '18 at 20:12