How to turn multiple observables an observable that emits once when all the source observables complete?












0














I'm calling an API method (using Angular's HttpClient several times as part of a form submission. (It adds a thing into another thing and our backend guys flat out refused to give me a batch-add method. So I call it once for every item the user enters.) The code is something like this (using lodash for data massaging):



const items = ['foo', 'bar', 'baz', 'quux'];
const result$: Observable = _.map(items, it => httpClient.post('/items', it));


I tried combining them using forkJoin:



forkJoin(result$).subscribe(resp => ..., err => ...);


But that revealed some sort of bug in the back-end where it throws when I do this for multiple items, but doesn't if I add them one-by-one. (Race condition I'm guessing.)



I tried getting around this by using concat() to make the client do the requests one-by-one:



concat(result$).subscribe(resp => ..., err => ...);


But that fires the subscription once for every source observable, I only want to know when they all complete (or don't.) How do I get the behaviour of forkJoin, except with the source observables not being subscribed to concurrently?










share|improve this question


















  • 1




    concat(...).pipe(ignoreElements()) will either complete (but emit no values) or error.
    – cartant
    Nov 21 at 2:30












  • @cartant - well, that at least pointed me in the right direction, now I know I can pass a complete callback to subscribe()
    – millimoose
    Nov 21 at 2:32










  • This reads like you already know the answer.
    – Stefan Hanke
    Nov 21 at 5:34










  • @StefanHanke - I’ll either answerify what I have or nule this question since it’s a pretty basic API thing and I also have an unrelated bug in the question code; I’ll decide after finishing this all-nighter and catching at least a little sleep
    – millimoose
    Nov 21 at 5:37










  • OT, but you should tell your backend guys that doing this one by one is not only a scaling issue (user needs to wait n times as long), but also an issue of transactionality (usually you want all to succeed or fail, not get an intermediate state) and atomicity (user leaves page mid-stream will execute only half the requests). Also, maybe if they don't give you the endpoint, they should at least fix that bug. Not serving an endpoint concurrently is outrageous. Your backend guys are wrong here, very wrong.
    – Ingo Bürk
    Nov 21 at 7:00


















0














I'm calling an API method (using Angular's HttpClient several times as part of a form submission. (It adds a thing into another thing and our backend guys flat out refused to give me a batch-add method. So I call it once for every item the user enters.) The code is something like this (using lodash for data massaging):



const items = ['foo', 'bar', 'baz', 'quux'];
const result$: Observable = _.map(items, it => httpClient.post('/items', it));


I tried combining them using forkJoin:



forkJoin(result$).subscribe(resp => ..., err => ...);


But that revealed some sort of bug in the back-end where it throws when I do this for multiple items, but doesn't if I add them one-by-one. (Race condition I'm guessing.)



I tried getting around this by using concat() to make the client do the requests one-by-one:



concat(result$).subscribe(resp => ..., err => ...);


But that fires the subscription once for every source observable, I only want to know when they all complete (or don't.) How do I get the behaviour of forkJoin, except with the source observables not being subscribed to concurrently?










share|improve this question


















  • 1




    concat(...).pipe(ignoreElements()) will either complete (but emit no values) or error.
    – cartant
    Nov 21 at 2:30












  • @cartant - well, that at least pointed me in the right direction, now I know I can pass a complete callback to subscribe()
    – millimoose
    Nov 21 at 2:32










  • This reads like you already know the answer.
    – Stefan Hanke
    Nov 21 at 5:34










  • @StefanHanke - I’ll either answerify what I have or nule this question since it’s a pretty basic API thing and I also have an unrelated bug in the question code; I’ll decide after finishing this all-nighter and catching at least a little sleep
    – millimoose
    Nov 21 at 5:37










  • OT, but you should tell your backend guys that doing this one by one is not only a scaling issue (user needs to wait n times as long), but also an issue of transactionality (usually you want all to succeed or fail, not get an intermediate state) and atomicity (user leaves page mid-stream will execute only half the requests). Also, maybe if they don't give you the endpoint, they should at least fix that bug. Not serving an endpoint concurrently is outrageous. Your backend guys are wrong here, very wrong.
    – Ingo Bürk
    Nov 21 at 7:00
















0












0








0







I'm calling an API method (using Angular's HttpClient several times as part of a form submission. (It adds a thing into another thing and our backend guys flat out refused to give me a batch-add method. So I call it once for every item the user enters.) The code is something like this (using lodash for data massaging):



const items = ['foo', 'bar', 'baz', 'quux'];
const result$: Observable = _.map(items, it => httpClient.post('/items', it));


I tried combining them using forkJoin:



forkJoin(result$).subscribe(resp => ..., err => ...);


But that revealed some sort of bug in the back-end where it throws when I do this for multiple items, but doesn't if I add them one-by-one. (Race condition I'm guessing.)



I tried getting around this by using concat() to make the client do the requests one-by-one:



concat(result$).subscribe(resp => ..., err => ...);


But that fires the subscription once for every source observable, I only want to know when they all complete (or don't.) How do I get the behaviour of forkJoin, except with the source observables not being subscribed to concurrently?










share|improve this question













I'm calling an API method (using Angular's HttpClient several times as part of a form submission. (It adds a thing into another thing and our backend guys flat out refused to give me a batch-add method. So I call it once for every item the user enters.) The code is something like this (using lodash for data massaging):



const items = ['foo', 'bar', 'baz', 'quux'];
const result$: Observable = _.map(items, it => httpClient.post('/items', it));


I tried combining them using forkJoin:



forkJoin(result$).subscribe(resp => ..., err => ...);


But that revealed some sort of bug in the back-end where it throws when I do this for multiple items, but doesn't if I add them one-by-one. (Race condition I'm guessing.)



I tried getting around this by using concat() to make the client do the requests one-by-one:



concat(result$).subscribe(resp => ..., err => ...);


But that fires the subscription once for every source observable, I only want to know when they all complete (or don't.) How do I get the behaviour of forkJoin, except with the source observables not being subscribed to concurrently?







javascript typescript rxjs






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 21 at 2:17









millimoose

32.1k761102




32.1k761102








  • 1




    concat(...).pipe(ignoreElements()) will either complete (but emit no values) or error.
    – cartant
    Nov 21 at 2:30












  • @cartant - well, that at least pointed me in the right direction, now I know I can pass a complete callback to subscribe()
    – millimoose
    Nov 21 at 2:32










  • This reads like you already know the answer.
    – Stefan Hanke
    Nov 21 at 5:34










  • @StefanHanke - I’ll either answerify what I have or nule this question since it’s a pretty basic API thing and I also have an unrelated bug in the question code; I’ll decide after finishing this all-nighter and catching at least a little sleep
    – millimoose
    Nov 21 at 5:37










  • OT, but you should tell your backend guys that doing this one by one is not only a scaling issue (user needs to wait n times as long), but also an issue of transactionality (usually you want all to succeed or fail, not get an intermediate state) and atomicity (user leaves page mid-stream will execute only half the requests). Also, maybe if they don't give you the endpoint, they should at least fix that bug. Not serving an endpoint concurrently is outrageous. Your backend guys are wrong here, very wrong.
    – Ingo Bürk
    Nov 21 at 7:00
















  • 1




    concat(...).pipe(ignoreElements()) will either complete (but emit no values) or error.
    – cartant
    Nov 21 at 2:30












  • @cartant - well, that at least pointed me in the right direction, now I know I can pass a complete callback to subscribe()
    – millimoose
    Nov 21 at 2:32










  • This reads like you already know the answer.
    – Stefan Hanke
    Nov 21 at 5:34










  • @StefanHanke - I’ll either answerify what I have or nule this question since it’s a pretty basic API thing and I also have an unrelated bug in the question code; I’ll decide after finishing this all-nighter and catching at least a little sleep
    – millimoose
    Nov 21 at 5:37










  • OT, but you should tell your backend guys that doing this one by one is not only a scaling issue (user needs to wait n times as long), but also an issue of transactionality (usually you want all to succeed or fail, not get an intermediate state) and atomicity (user leaves page mid-stream will execute only half the requests). Also, maybe if they don't give you the endpoint, they should at least fix that bug. Not serving an endpoint concurrently is outrageous. Your backend guys are wrong here, very wrong.
    – Ingo Bürk
    Nov 21 at 7:00










1




1




concat(...).pipe(ignoreElements()) will either complete (but emit no values) or error.
– cartant
Nov 21 at 2:30






concat(...).pipe(ignoreElements()) will either complete (but emit no values) or error.
– cartant
Nov 21 at 2:30














@cartant - well, that at least pointed me in the right direction, now I know I can pass a complete callback to subscribe()
– millimoose
Nov 21 at 2:32




@cartant - well, that at least pointed me in the right direction, now I know I can pass a complete callback to subscribe()
– millimoose
Nov 21 at 2:32












This reads like you already know the answer.
– Stefan Hanke
Nov 21 at 5:34




This reads like you already know the answer.
– Stefan Hanke
Nov 21 at 5:34












@StefanHanke - I’ll either answerify what I have or nule this question since it’s a pretty basic API thing and I also have an unrelated bug in the question code; I’ll decide after finishing this all-nighter and catching at least a little sleep
– millimoose
Nov 21 at 5:37




@StefanHanke - I’ll either answerify what I have or nule this question since it’s a pretty basic API thing and I also have an unrelated bug in the question code; I’ll decide after finishing this all-nighter and catching at least a little sleep
– millimoose
Nov 21 at 5:37












OT, but you should tell your backend guys that doing this one by one is not only a scaling issue (user needs to wait n times as long), but also an issue of transactionality (usually you want all to succeed or fail, not get an intermediate state) and atomicity (user leaves page mid-stream will execute only half the requests). Also, maybe if they don't give you the endpoint, they should at least fix that bug. Not serving an endpoint concurrently is outrageous. Your backend guys are wrong here, very wrong.
– Ingo Bürk
Nov 21 at 7:00






OT, but you should tell your backend guys that doing this one by one is not only a scaling issue (user needs to wait n times as long), but also an issue of transactionality (usually you want all to succeed or fail, not get an intermediate state) and atomicity (user leaves page mid-stream will execute only half the requests). Also, maybe if they don't give you the endpoint, they should at least fix that bug. Not serving an endpoint concurrently is outrageous. Your backend guys are wrong here, very wrong.
– Ingo Bürk
Nov 21 at 7:00














1 Answer
1






active

oldest

votes


















0














You can use concatMap




concatMap: it's maping values to inner observable, subscribe and emit
in order.




In your case forkJoin is doing all subscriptions at the same time, but concatMap should do them one by one.



I hope this is useful to you






share|improve this answer





















  • Sorry, no, concatMap still emits once for every time a source observable emits.
    – millimoose
    Nov 21 at 2:29










  • can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
    – Microsmsm
    Nov 21 at 2:41













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%2f53404422%2fhow-to-turn-multiple-observables-an-observable-that-emits-once-when-all-the-sour%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









0














You can use concatMap




concatMap: it's maping values to inner observable, subscribe and emit
in order.




In your case forkJoin is doing all subscriptions at the same time, but concatMap should do them one by one.



I hope this is useful to you






share|improve this answer





















  • Sorry, no, concatMap still emits once for every time a source observable emits.
    – millimoose
    Nov 21 at 2:29










  • can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
    – Microsmsm
    Nov 21 at 2:41


















0














You can use concatMap




concatMap: it's maping values to inner observable, subscribe and emit
in order.




In your case forkJoin is doing all subscriptions at the same time, but concatMap should do them one by one.



I hope this is useful to you






share|improve this answer





















  • Sorry, no, concatMap still emits once for every time a source observable emits.
    – millimoose
    Nov 21 at 2:29










  • can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
    – Microsmsm
    Nov 21 at 2:41
















0












0








0






You can use concatMap




concatMap: it's maping values to inner observable, subscribe and emit
in order.




In your case forkJoin is doing all subscriptions at the same time, but concatMap should do them one by one.



I hope this is useful to you






share|improve this answer












You can use concatMap




concatMap: it's maping values to inner observable, subscribe and emit
in order.




In your case forkJoin is doing all subscriptions at the same time, but concatMap should do them one by one.



I hope this is useful to you







share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 21 at 2:28









Microsmsm

1,8851624




1,8851624












  • Sorry, no, concatMap still emits once for every time a source observable emits.
    – millimoose
    Nov 21 at 2:29










  • can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
    – Microsmsm
    Nov 21 at 2:41




















  • Sorry, no, concatMap still emits once for every time a source observable emits.
    – millimoose
    Nov 21 at 2:29










  • can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
    – Microsmsm
    Nov 21 at 2:41


















Sorry, no, concatMap still emits once for every time a source observable emits.
– millimoose
Nov 21 at 2:29




Sorry, no, concatMap still emits once for every time a source observable emits.
– millimoose
Nov 21 at 2:29












can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
– Microsmsm
Nov 21 at 2:41






can skipUntil help you here? rxjs-dev.firebaseapp.com/api/operators/skipUntil
– Microsmsm
Nov 21 at 2:41




















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.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • 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%2f53404422%2fhow-to-turn-multiple-observables-an-observable-that-emits-once-when-all-the-sour%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

404 Error Contact Form 7 ajax form submitting

How to know if a Active Directory user can login interactively

Refactoring coordinates for Minecraft Pi buildings written in Python