rxjs conditional nesting observables











up vote
1
down vote

favorite












I have the following code which is working as intended:





const sourceObservable = ... // irrelevant
sourceObservable.subscribe(x => {
doAnyway(x);
if (x.Id) {
doSometing(x);
} else {
// id Not set, get default Id
this.idService.getDefault().subscribe(id => {
x.Id = id;
doSometing(x);
});
}
});


According to this article nested subscribes are to avoid. Thats why i tried to refactor the above code, using pipes. I tried to realize the if-else operation with this Method, where filtering is used to create an observable branch for each option. And in the end they should be merged to subscribe.



const obsShared = sourceObservable.pipe(
tap(x => {
doAnyway(x);
}),
share());

const obsIdNotSet = obsShared.pipe(
filter(x => !x.kennzahlId),
merge(x => idService.getDefault().subscribe(id => {
x.Id = id;
// doSomething(x) will nomore be executed here
})));

// even though the true-part is empty I seem to need this to mergeing both options
const obsIdSet = obsShared.pipe(
filter(x => !!x.Id),
tap(() => {
// doSomething(x) will nomore be executed here
}));

obsIdSet.pipe(merge(obsIdNotSet)).subscribe(x => {
// in case obsIdNotSet this will run with x.Id not set because x.Id will be set later
doSometing(x);
});


This code does compile and run without errors, only does it execute doSomething(x) before calling idService.getDefault()..... and though it will be called without x.Id being set.



What am i doing wrong?










share|improve this question




























    up vote
    1
    down vote

    favorite












    I have the following code which is working as intended:





    const sourceObservable = ... // irrelevant
    sourceObservable.subscribe(x => {
    doAnyway(x);
    if (x.Id) {
    doSometing(x);
    } else {
    // id Not set, get default Id
    this.idService.getDefault().subscribe(id => {
    x.Id = id;
    doSometing(x);
    });
    }
    });


    According to this article nested subscribes are to avoid. Thats why i tried to refactor the above code, using pipes. I tried to realize the if-else operation with this Method, where filtering is used to create an observable branch for each option. And in the end they should be merged to subscribe.



    const obsShared = sourceObservable.pipe(
    tap(x => {
    doAnyway(x);
    }),
    share());

    const obsIdNotSet = obsShared.pipe(
    filter(x => !x.kennzahlId),
    merge(x => idService.getDefault().subscribe(id => {
    x.Id = id;
    // doSomething(x) will nomore be executed here
    })));

    // even though the true-part is empty I seem to need this to mergeing both options
    const obsIdSet = obsShared.pipe(
    filter(x => !!x.Id),
    tap(() => {
    // doSomething(x) will nomore be executed here
    }));

    obsIdSet.pipe(merge(obsIdNotSet)).subscribe(x => {
    // in case obsIdNotSet this will run with x.Id not set because x.Id will be set later
    doSometing(x);
    });


    This code does compile and run without errors, only does it execute doSomething(x) before calling idService.getDefault()..... and though it will be called without x.Id being set.



    What am i doing wrong?










    share|improve this question


























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I have the following code which is working as intended:





      const sourceObservable = ... // irrelevant
      sourceObservable.subscribe(x => {
      doAnyway(x);
      if (x.Id) {
      doSometing(x);
      } else {
      // id Not set, get default Id
      this.idService.getDefault().subscribe(id => {
      x.Id = id;
      doSometing(x);
      });
      }
      });


      According to this article nested subscribes are to avoid. Thats why i tried to refactor the above code, using pipes. I tried to realize the if-else operation with this Method, where filtering is used to create an observable branch for each option. And in the end they should be merged to subscribe.



      const obsShared = sourceObservable.pipe(
      tap(x => {
      doAnyway(x);
      }),
      share());

      const obsIdNotSet = obsShared.pipe(
      filter(x => !x.kennzahlId),
      merge(x => idService.getDefault().subscribe(id => {
      x.Id = id;
      // doSomething(x) will nomore be executed here
      })));

      // even though the true-part is empty I seem to need this to mergeing both options
      const obsIdSet = obsShared.pipe(
      filter(x => !!x.Id),
      tap(() => {
      // doSomething(x) will nomore be executed here
      }));

      obsIdSet.pipe(merge(obsIdNotSet)).subscribe(x => {
      // in case obsIdNotSet this will run with x.Id not set because x.Id will be set later
      doSometing(x);
      });


      This code does compile and run without errors, only does it execute doSomething(x) before calling idService.getDefault()..... and though it will be called without x.Id being set.



      What am i doing wrong?










      share|improve this question















      I have the following code which is working as intended:





      const sourceObservable = ... // irrelevant
      sourceObservable.subscribe(x => {
      doAnyway(x);
      if (x.Id) {
      doSometing(x);
      } else {
      // id Not set, get default Id
      this.idService.getDefault().subscribe(id => {
      x.Id = id;
      doSometing(x);
      });
      }
      });


      According to this article nested subscribes are to avoid. Thats why i tried to refactor the above code, using pipes. I tried to realize the if-else operation with this Method, where filtering is used to create an observable branch for each option. And in the end they should be merged to subscribe.



      const obsShared = sourceObservable.pipe(
      tap(x => {
      doAnyway(x);
      }),
      share());

      const obsIdNotSet = obsShared.pipe(
      filter(x => !x.kennzahlId),
      merge(x => idService.getDefault().subscribe(id => {
      x.Id = id;
      // doSomething(x) will nomore be executed here
      })));

      // even though the true-part is empty I seem to need this to mergeing both options
      const obsIdSet = obsShared.pipe(
      filter(x => !!x.Id),
      tap(() => {
      // doSomething(x) will nomore be executed here
      }));

      obsIdSet.pipe(merge(obsIdNotSet)).subscribe(x => {
      // in case obsIdNotSet this will run with x.Id not set because x.Id will be set later
      doSometing(x);
      });


      This code does compile and run without errors, only does it execute doSomething(x) before calling idService.getDefault()..... and though it will be called without x.Id being set.



      What am i doing wrong?







      angular typescript rxjs






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited yesterday









      trichetriche

      23.5k41949




      23.5k41949










      asked yesterday









      LuckyLikey

      1,1851029




      1,1851029
























          1 Answer
          1






          active

          oldest

          votes

















          up vote
          4
          down vote



          accepted










          the following is the cleanest way to handle that (according to me) :



          source.pipe(
          tap(val => doAnyway(val)),
          switchMap(val => val.id ? of(val.id) : this.idService.getDefault())
          ).subscribe(id => {
          this.id = id;
          doSomething(id);
          });


          You can see how short and clear this is, and it does the exact same thing your first code was doing.






          share|improve this answer





















          • could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
            – LuckyLikey
            yesterday










          • Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
            – trichetriche
            yesterday










          • you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
            – LuckyLikey
            yesterday












          • @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
            – trichetriche
            yesterday






          • 1




            Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
            – trichetriche
            yesterday











          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',
          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%2f53372350%2frxjs-conditional-nesting-observables%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








          up vote
          4
          down vote



          accepted










          the following is the cleanest way to handle that (according to me) :



          source.pipe(
          tap(val => doAnyway(val)),
          switchMap(val => val.id ? of(val.id) : this.idService.getDefault())
          ).subscribe(id => {
          this.id = id;
          doSomething(id);
          });


          You can see how short and clear this is, and it does the exact same thing your first code was doing.






          share|improve this answer





















          • could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
            – LuckyLikey
            yesterday










          • Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
            – trichetriche
            yesterday










          • you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
            – LuckyLikey
            yesterday












          • @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
            – trichetriche
            yesterday






          • 1




            Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
            – trichetriche
            yesterday















          up vote
          4
          down vote



          accepted










          the following is the cleanest way to handle that (according to me) :



          source.pipe(
          tap(val => doAnyway(val)),
          switchMap(val => val.id ? of(val.id) : this.idService.getDefault())
          ).subscribe(id => {
          this.id = id;
          doSomething(id);
          });


          You can see how short and clear this is, and it does the exact same thing your first code was doing.






          share|improve this answer





















          • could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
            – LuckyLikey
            yesterday










          • Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
            – trichetriche
            yesterday










          • you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
            – LuckyLikey
            yesterday












          • @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
            – trichetriche
            yesterday






          • 1




            Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
            – trichetriche
            yesterday













          up vote
          4
          down vote



          accepted







          up vote
          4
          down vote



          accepted






          the following is the cleanest way to handle that (according to me) :



          source.pipe(
          tap(val => doAnyway(val)),
          switchMap(val => val.id ? of(val.id) : this.idService.getDefault())
          ).subscribe(id => {
          this.id = id;
          doSomething(id);
          });


          You can see how short and clear this is, and it does the exact same thing your first code was doing.






          share|improve this answer












          the following is the cleanest way to handle that (according to me) :



          source.pipe(
          tap(val => doAnyway(val)),
          switchMap(val => val.id ? of(val.id) : this.idService.getDefault())
          ).subscribe(id => {
          this.id = id;
          doSomething(id);
          });


          You can see how short and clear this is, and it does the exact same thing your first code was doing.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered yesterday









          trichetriche

          23.5k41949




          23.5k41949












          • could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
            – LuckyLikey
            yesterday










          • Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
            – trichetriche
            yesterday










          • you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
            – LuckyLikey
            yesterday












          • @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
            – trichetriche
            yesterday






          • 1




            Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
            – trichetriche
            yesterday


















          • could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
            – LuckyLikey
            yesterday










          • Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
            – trichetriche
            yesterday










          • you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
            – LuckyLikey
            yesterday












          • @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
            – trichetriche
            yesterday






          • 1




            Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
            – trichetriche
            yesterday
















          could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
          – LuckyLikey
          yesterday




          could I also provide a mapping function to map the result of this.idService.getDefault() if the result wasn't an Id itself?
          – LuckyLikey
          yesterday












          Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
          – trichetriche
          yesterday




          Sure, this.idService.getDefault().pipe(map(...)) (you can use pipes within pipes, there's no issue with that)
          – trichetriche
          yesterday












          you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
          – LuckyLikey
          yesterday






          you must truly be my captain :) Added import 'rxjs/add/observable/of'; but it doesn't seem to be found. Im using angular 6
          – LuckyLikey
          yesterday














          @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
          – trichetriche
          yesterday




          @LuckyLikey if it works for you, consider leaving an upvote and/or closing your question as resolved !
          – trichetriche
          yesterday




          1




          1




          Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
          – trichetriche
          yesterday




          Exactly. And to explain the difference, combineLatest as static (non-pipeable) signature take at least 2 observables, while combineLatest as instance method can take only one (the second one being the "piped" first observable). See this stackblitz to see the difference in syntax !
          – trichetriche
          yesterday


















           

          draft saved


          draft discarded



















































           


          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53372350%2frxjs-conditional-nesting-observables%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

          Can a sorcerer learn a 5th-level spell early by creating spell slots using the Font of Magic feature?

          Does disintegrating a polymorphed enemy still kill it after the 2018 errata?

          A Topological Invariant for $pi_3(U(n))$