1
votes

I'm trying to follow the "Observable data store" pattern in Angular 2 (detailed in this blog post from Angular University) From what I understand, this means that, if I have a service called TodoStore, I would subscribe to TodoStore.items$ so I could get all the latest updates for my to-do list in real time (as other components add, remove, or edit Todos.

However, what if I have two components side-by-side that display different Todolists, filtered on the server-side? One might display Todos due today while another would show Todos due on a user-selected date.

In this case, I would not be able to use the same TodoStore, as both would be fetching different data from the server. How do I handle sharing this service between these two components? My urge is to go back to an angular1-style getToDoList() service method, but then I'm storing state inside a single component and can't possibly share data between multiple components without making extra API calls.

1
Is it two different components side-by-side or two instances of the same component side-by-side? Please add some code, at least the minimum needed to clarify your question.ppovoski
Why don't you use something like TodoStore.getItemsFromList(name)?olivarra1

1 Answers

1
votes

If your lists really have to be filtered server-side and you have an unknown number of simultaneously displayed lists and a new server-request has to me made for each list + filter, then it is perfectly possible that using a single observable (TodoStore.items$) might not be a viable solution here and maybe some kind of getTodoList(forFilter) might be easier/quicker to implement.

Remeber: There is no such thing as "The perfect solution for all cases."

However: Even in this case you could use a store, which could something like this:

interface ITodoListDictionary {
    [key: string]: Todo[];
}

@Injectable()
export class TodoStore {
    todoLists$: BehaviorSubject<ITodoListDictionary> = new BehaviorSubject<ITodoListDictionary>({});

    getListByKey(key: string): Observable<Todo[]> {
        return this.todoLists$
            .pluck(key)
            .distinctUntilChanged() // optional, so you only get the update if there is an actually new list
            .share();
    }

    // this would be called whenever the rest-response for a given list arrives
    setListByKey(key: string, list: Todo[]): void {
        this.todoLists$.take(1)
            .do(dict => {
                const newDict = Object.assign({}, dict, {[key]: list});
                // if you are using TS2.1 you could also use:
                // const newDict = {...dict, {[key]: list}};
                this.todoLists$.next(newDict);
            })
            .subscribe();
    }
}

...and in your template you could use it like this

<todo *ngFor="let todo of todoStore.getListByKey(someKey) | async" todo="todo"></todo>

Please keep in mind that is just one possible solution out of many - without seeing your actual application-flow it is hard to tell which might be the best solition.