1

My view has three fields, which together form an equation. What I want to achieve is as soon as the user fills in 2 out of 3 fields, I calculate the remaining one.

What I have:

mObservableEditTextA = RxTextView.textChanges(mEditTextA);
mObservableEditTextB = RxTextView.textChanges(mEditTextB);
mObservableEditTextC = RxTextView.textChanges(mEditTextC);

I tried to for each pair of fields get the combine latest of the other two with no success.

Observable.combineLatest(mObservableEditTextA, mObservableEditTextB, (a, b) -> /* My action here */);
Observable.combineLatest(mObservableEditTextA, mObservableEditTextC, (a, c) -> /* My action here */);
Observable.combineLatest(mObservableEditTextB, mObservableEditTextC, (b, c) -> /* My action here */);

How can I achieve this behavior?

thyago stall
  • 1,654
  • 3
  • 16
  • 30

1 Answers1

0

There is probably a better way to go, but you could attach a timestamp of emission to each event, determine which of them was last and emit the rest. Identify those events by the observable ( field ) from which they have come and decide by the element which is missing in the list.

mObservableEditTextA = RxTextView.textChanges(mEditTextA)
    .debounce(500, TimeUnit.MILLISECONDS) // So we don't flood the heap with lots of object construction, creating performance overhead due to garbage collection
    .map(text -> Pair.create(new Date(), text));
mObservableEditTextB = RxTextView.textChanges(mEditTextB)
    .debounce(500, TimeUnit.MILLISECONDS)
    .map(text -> Pair.create(new Date(), text));
mObservableEditTextC = RxTextView.textChanges(mEditTextC)
    .debounce(500, TimeUnit.MILLISECONDS)
    .map(text -> Pair.create(new Date(), text));

Observable.combineLatest(mObservableEditTextA, mObservableEditTextB, mObservableEditTextC, (fieldAPair, fieldBPair, fieldCPair) -> {
        firstField = ...;
        secondField = ...;
        // from timestamps determine which of the fields emitted last and return the other two with identifiers
        return Arrays.asList(Pair.create(firstFieldIdentifier, firstField), Pair.create(secondFieldIdentifier, secondField));
    })
    .subscribe(result -> {
        /* result is always a list of 2 items, more specifically 
           pairs of an identification in first position and new text 
           in the second. 

           Here you can look for the missing field in the list and 
           compute it from the other two */
    })

The logic for determining which one do you want to compute is duplicated here. I did that just for the reason of not having to wrap those objects in a new object and nested Pairs lose readability.

You could however treat the position in a list as an identifier for the field although that is prone to mistakes.

Any of those approaches would move the determining logic from both subscriber and combineLatest operator only to subscriber itself. Your call.

koperko
  • 2,447
  • 13
  • 19