skip to Main Content

I have the following piece of code:

  readonly todos$: Observable<Todo[]> = combineLatest([this.account$, this.loadTodoPage$]).pipe(
    concatMap(([account, pageNo]) => this.todoService.getTodos(account.id, pageNo)),
    scan((acc: Todo[], curr: Todo[]) => [...acc, ...curr], [])
  );

This always loads a new page of todos from the backend when i emit a new value in the loadTodoPage subject.

Now I need to integrate a third subject in this logic which is responsible for discarding or reopen the todo. The Subject should like like this:
readonly modifyTodo$: Subject<{ action: 'discard' | 'reopen'; todo: Todo }> = new Subject();

When I integrate the subject after the scan operator, the scan will always override the modifications and if I integrate the the subject within the combineLatest it will always also fetch new todos from the backend which is not what I want.

Can someone give me an hint how I can solve this in a declarative approach?

2

Answers


  1. So if I understand well, you have

    • fetchedTodos$ for the call to the backend

      const fetchedTodos$ = combineLatest([this.account$, this.loadTodoPage$]).pipe(
           concatMap(([account, pageNo]) => this.todoService.getTodos(account.id, pageNo)),
           scan((acc: Todo[], curr: Todo[]) => [...acc, ...curr], [])
      );
      
    • And modifyTodo$ with new todos.

    Then you can combine them together with a combineLatest as you have done it for the fetchedTodos$:

    const todos$ = combineLatest([fetchedTodos$,modifyTodo$]).pipe(
       map(([fetchedTodos,modifiedTodos])=> { ... })
    )
    
    Login or Signup to reply.
  2. I believe you could merge modifyTodo$ into the chain and then let scan() handle the logic that updates todos:

    type Command = { action: 'discard' | 'reopen'; todo: Todo };
    
    readonly todos$: Observable<Todo[]> = combineLatest([this.account$, this.loadTodoPage$]).pipe(
        concatMap(([account, pageNo]) => this.todoService.getTodos(account.id, pageNo)),
        mergeWith(modifyTodo$),
        scan((acc: Todo[], curr: Todo[] | Command) => {
            if (Array.isArray(curr)) {
                return [...acc, ...curr];
            }
    
            // Update todo
            const todo = acc.find(curr.todo.id);
            if (curr.action === 'discard') {
                todo.whatever = ...;
            } else {
                // ...
            } 
            
            return [...acc];
        }, [])
    );
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search