I like your question. I too always try to define my observables in a declarative way. However, when it comes to methods that take parameters (especially in Angular services), I tend to just use a just use functions that return observables:
class ItemService {
public getItem(id: string) {
return this.http.get<Item>(`${this.apiRoot}/items/${id}`);
}
}
If the service itself is responsible for managing the state of these "parameters", then it makes sense to use subjects like @DeborahK has mentioned, to provide a facility for consumers to pass in values.
However, if the component is responsible for these parameters, then it's not usually necessary to have Subjects because those param values usually come from other observable sources like reactive form controls or route params.
For example:
class ItemComponent {
private id$ = this.route.paramMap.pipe(params => params.get('id'));
public item$ = this.id$.pipe(
switchMap(id => this.itemService.getItem(id))
);
constructor(
private route: ActivatedRoute,
private itemService: ItemService
) { }
}
Notice in the component, item$
is still defined in that declarative way that you like. Also notice, I do what @DeborahK mentioned and define it from another stream (the other stream just happens to be a different observable, instead of a subject).