问题
Using Angular 7 I have the following service (StackBlitz Example):
@Injectable({
providedIn: 'root'
})
export class TodoService {
todos: BehaviorSubject<Todo[]> = new BehaviorSubject([
{ id: 1, title: "Buy book", content: "Buy book about angular" },
{ id: 2, title: "Send invoice", content: "Send invoice to client A" }
]);
public get(): Observable<Todo[]> {
return this.todos.asObservable();
}
public create(todo: Todo) {
this.todos.next(this.todos.value.concat(todo));
}
}
This service is used by a few components:
- TodoCreateComponent > Creates new todo
- TodoListComponent > Shows list of todos
- TodoRecentComponent > Shows recent todos
Each component has its own model mapped from a Todo
in its own way ...
Some models use many Todo
properties (Title
, Content
), others only one (Title
) etc.
On my StackBlitz Example a new Todo
is, automatically, added to the todo list:
Objective
Now I need to replace the local data by data taken from an API:
public get(): Observable<Todo[]> {
return this.httpClient.get<Todo>(`todos`);
}
public create(todo: Todo) {
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
this.httpClient.post(`todos`, todo, { headers: headers });
}
Question
The question is how to integrate HttpClient to get everything in sync:
So when a new Todo
is created the list of Todos
should be updated ...
回答1:
Use a notification service to tell the list component to repoll the server.
export class RepollTodosNotificationService {
subject: ReplaySubject<any> = new ReplaySubject();
obs: Observable<any> = this.subject.asObservable;
notify = (data: any) => {
this.subject.next(data)
}
}
Make service a singleton:
(app.module.ts)
@NgModule({
providers: [RepollTodosNotificationService]
})
In TodoCreateComponent
this.todoSevice.post(myNewTodo)
.subscribe(
result => {
// current callback code
this.repollNotifierService.notify(null); // null or data you want to send
In TodoListComponent
export class TodoListComponent implements OnInit, OnDestroy {
private repollSubscription: Subscription;
constructor(private repollSvc: RepollTodosNotificationService) {}
ngOnInit() {
this.repollSvc.obs.subscribe(() => this.fetchTodos()); // if you transfer data, handle here
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
// methods
}
回答2:
One way to stay sync is to update your BehaviorSubject upon the response of your API using the RxJS operator tap
, for example:
public get(): Observable<Todo[]> {
return this.httpClient.get<Todo>(`todos`)
.pipe(tap(todo => this.todos.next(todos)))
}
or
public create(todo): Observable<Todo[]> {
return this.httpClient.post<Todo>(`apiUrl`, todo)
.pipe(tap(todo => // do something with the todo ))
}
来源:https://stackoverflow.com/questions/56116905/update-list-when-new-item-is-added