1

I'm using RxJS to listen to a form submit event, and submit it over AJAX (it's a weird bit of code, but I'm just experimenting with RxJS for now, so bear with me). What I want to do is only allow submissions when a request is not in progress.

My code so far looks like this (and is "working"):

Rx.DOM.submit(formEl)
  .map(function(event){ event.preventDefault(); return event; })
  .map(function(){ return getEmailAddress(formEl); })
  .subscribe(function(email){
    submitToMailChimp(url, email).done(showMailChimpThanks(orbitInstance)).fail(showMailChimpError);
  });

My problem is I'm not sure how to implement something that will accomodate for this limitation (saw skipUntil but not quite sure how to handle that in this case). So my questions are: how do I (a) block submission until my Ajax request is done and (b) optimise my code to have the Ajax request at the end of the chain, so I can subscribe to the result of it, instead of this weird hybrid mish-mash.

Final solution:

var submissions = Rx.DOM.submit(formEl);

submissions.subscribe(preventDefaultEvent);

var requests = submissions
  .first()
  .map(getEmailAddress(formEl))
  .flatMap(submitToMailChimp(url))
  .catch(showMailChimpError(submitButton))
  .repeat();

requests.subscribe(showMailChimpThanks(orbitInstance, submitButton));
Steven
  • 1,566
  • 2
  • 16
  • 38

1 Answers1

3

Great question. Use first() after the submit to only allow one submission, and after the ajax request completes (which we will call via flatMap), this observable will complete (because of first). So we append a repeat() to start listening for the next submit once the first one completes. Because I suppose you do not want to stop the stream if one of the ajax calls fails, we'll turn the results of your ajax request into either an Error or the results and stream this "Either" through as data (see this question)

The tricky part is that you also want to ensure you call preventDefault every time even while a current submission is being processed and we are not currently listening for submit. In my mind, this is a different action with different observation requirements and so we should just write it as a separate query. Thus we end up with:

var submissions = Rx.DOM.submit(formEl);

// send ajax requests on submissions
submissions
    .first()
    .flatMap(function (event) {
        var email = getEmailAddress(formEl);
        return submitToMailChimp(url, email)
            .then(
                function (v) { return v; },
                function (e) { return new Error(e); });
    })
    .repeat()
    .subscribe(function (result) {
        if (result instanceof Error) {
            showMailChimpError(result);
        }
        else {
            showMailChimpThanks(instance);
        }
    });

// prevent defaults
submissions.subscribe(function (ev) { ev.preventDefault(); });
Community
  • 1
  • 1
Brandon
  • 38,310
  • 8
  • 82
  • 87
  • Hey Brandon! Thanks, that helped alot. I eventually solved it with a `catch` in my stream, like so: https://gist.github.com/StevenLangbroek/13b7d02287e948509d78. This really helped me understand the logic behind why it's failing though, so thanks a million! – Steven Jan 08 '15 at 16:41