1

I have multiple inputs that are created dynamically (Can add or delete inputs). and a text field that shows the sum of the inputs. How can I attach observable dynamically and how can my text subscribe to all of them?

Since I am not able to figure out how to create and attach observables to field or how to access them using their id maybe. I don't have much code to post! Any input ?

Function has loop and returns list of obeservables

    var source = Rx.Observable.fromEvent(cellVal, 'keyup',(evt) => evt.target.value).startWith(cellVal.value);
    arr.push(source); 
    }
    return arr;


    values = funct() //calls function that returns array of obervables
    var example = Rx.Observable.combineLatest(values);
    example.subscribe(val => {
        console.log('Sum:', val);
    });

The inputs can be created or deleted and sum shud be updated accordingly

Delfin
  • 607
  • 7
  • 18
  • How are your inputs created dynamically? Can you give an example. Are those multiple Observable> or is it just one Observable with changing arrays over time? – Jonathan Stellwag Mar 06 '20 at 16:36
  • I just updated the question for more details. Please have a look – Delfin Mar 06 '20 at 16:55
  • Is the answer provided fitting to you? Or do you have any questions? It's a pretty high effort to write detailed answers and I would like to have at least feedback if it's understood – Jonathan Stellwag May 27 '20 at 07:17

1 Answers1

0

If you want to add/delete observables over time to an array that means you need a state (because of add/delete). If you want to stick to rxjs the only non-side-effect way I know is to use the scan operator. Following code shows an implementation:

Interface

interface MappableObservable <T>{
  key: number,
  observable: Observable<T>
}

Functions

// Function that adds to an array of MappableObservables
const addToState = (update: MappableObservable<string>) => (state: MappableObservable<string>[]): MappableObservable<string>[] => 
  [...state, update];

// Function that deletes all items with given key from an array of MappableObservables
const deleteFromState = (key: number) => (state: MappableObservable<string>[]): MappableObservable<string>[] =>
  state.filter(item => item.key !== key);

// Function that executes the above add or delete function inside a scan
const scanFn = (state: MappableObservable<string>[], fn: (state: MappableObservable<string>[]) => MappableObservable<string>[]) =>
  fn(state)

Execution

const DEFAULT_MAPPABLE_OBSERVABLE_STATE: MappableObservable<string>[] = [];
const add$: Subject<MappableObservable<string>> = new Subject();
const delete$: Subject<number> = new Subject();

const source$: Observable<string[]> = merge(
  add$.pipe(map(addToState)),
  delete$.pipe(map(deleteFromState))
).pipe(
  scan(scanFn, DEFAULT_MAPPABLE_OBSERVABLE_STATE),
  map(state => state.map(mappableObservable => mappableObservable.observable)),
  switchMap(observables => combineLatest(observables))
)

Add or delete some observable to this source$

add$.next({key: 1, observable: of('uno')}) // Output: 'uno'
add$.next({key: 2, observable: of('duo')}) // Output: 'uno', 'duo'
add$.next({key: 3, observable: of('tri')}) // Output: 'uno', 'duo', 'tri'
add$.next({key: 2, observable: of('duo-duo')}) // Output: 'uno', 'duo', 'tri' 'duo-duo'
delete$.next(2); // Output: 'uno', 'tri'

FYI: The observables only directly if you replay them or use of(...) like i did in this example. If you have non replayed or instant observables they will only emit, when they all newly complete

Running stackblitz

Jonathan Stellwag
  • 3,843
  • 4
  • 25
  • 50