#angular #rxjs #observable
#angular #rxjs #наблюдаемый
Вопрос:
Я нахожусь в довольно затруднительном положении, и это мог бы быть подход, который я использовал, изучая RxJS и наблюдаемые.
Предисловие
Наше приложение использует Angular для подключения к нашему общедоступному уровню API (C #). Тип объекта, который возвращается из моего АСИНХРОННОГО вызова, имеет Observable< ListResultDtoOfNoteDto >. Этот поток передается дочернему компоненту, который перебирает элементы. Этот же поток также позволяет пользователю добавлять новые заметки типа NoteDto или редактировать заметки. В идеале, когда эти действия будут выполнены, список заметок будет отражать обновленные изменения без необходимости повторного вызова той же службы для получения заметок.
Код
[notes.component.html ]
<div *ngIf="(notes$ | async)?.items as notes; else loading">
<note-card [noteData]="notes" (noteClick)="editNote($event)"></note-card>
</div>
<ng-template #loading>
<div class="notes__container">
<div class="note-card">
<div class="note-card__primary-action">
<div class="note-card__head">
<h2 class="note-card__title note-card-typography--headline1 text-center">Loading...</h2>
</div>
</div>
</div>
</div>
</ng-template>
[примечания.component.ts]
import ...
@Component({
...
})
export class NotesComponent extends AppComponentBase implements OnInit {
constructor(
...
private _noteService: NoteServiceServiceProxy
) {
super(injector);
}
public notes$: Observable<ListResultDtoOfNoteDto>;
public userId: number;
...
ngOnInit() {
...
this.getNotes();
...
}
getNotes(): void {
/*
Binding to ASYNC pipe; which doesn't need a subscription since it is automatic?
Returns type: Observable<ListResultDtoOfNoteDto> which is an array of NoteDto
*/
this.notes$ = this._noteService.getUserNotes(this.userId, null);
...
}
...
public saveNote(note: NoteDto, mode: string) {
if (mode === 'new') {
this._noteService.addNote(note).subscribe(() => {
this.cleanUp();
this.getNotes();
this.notify.info(this.l('SavedNoteSuccessfully'));
});
}
...
}
}
Вся функциональность за вычетом ClickEvent в дочернем элементе выполняется внутри родительского элемента. Который загружает форму (методология реактивной формы), которая может создавать новую заметку и сохранять или редактировать старую заметку для обновления.
Моя проблема
Мне просто нужен способ сохранить заметку и обновить список без необходимости снова вызывать this.getNotes() в подписке при добавлении новой заметки.
(При необходимости я могу предоставить более подробную информацию!)
РЕДАКТИРОВАТЬ: Забыл показать метод сохранения в данный момент
Комментарии:
1. содержит ли ваш сервис notes прямой вызов api? если вы не хотите снова вызывать getNotes, вам нужно будет сохранить данные в сервисе и обновить эти данные после выполнения вызова add (обычно с помощью HTTP POST для создания объекта вы получите созданный объект обратно и, следовательно, сможете добавить этот объект в свой сервис, содержащий ваши данные). Если ваше приложение (многие компоненты) сильно полагаются на эту базу данных, возможно, стоит проверить github.com/ngrx/store в противном случае вы могли бы просто написать одноэлементный сервис, содержащий ваши данные.
2. Я не делаю этого технически в рамках this.notes $ = this._noteService.getUserNotes(<>) в моем методе getNotes()? Также, если вы посмотрите на мой метод SaveNotes (), я не думаю, что использую ASYNC должным образом, поскольку я снова вызываю GetNotes () и снова переделываю этот вызов службы
Ответ №1:
Один из способов, которым вы можете достичь этого, — иметь частный BehaviorSubject внутри вашего NoteServiceServiceProxy
, который всегда будет содержать последнее значение notes.
Нравится: private _notes = new BehaviorSubject<ListResultDtoOfNoteDto>(null)
- и вы публикуете функцию, которая предназначена только для подписки потребителей.
- Ваш вызов API обновит тему только с помощью ответа
public getNotes(): Observable<ListResultDtoOfNoteDto> {
return this._notes.asObservable();
}
public getNotesFromApi(args): {
// Api request
this.httpClient.get().pipe(tap(result) => this._notes.next(result))
// etc...
}
Затем все, что вам нужно сделать в вашем компоненте, это объявить ваш наблюдаемый объект примерно так
notesData = this. _noteService.getNotes();
внутри init
просто сделайте запрос к API, чтобы получить заметки, и он автоматически обновит ваш, notesData
который должен быть подписан на ваш шаблон через async
вывод канала.
При сохранении все, что вам нужно сделать, это просто добавить concatMap
в конце, чтобы сначала сохранить, а затем запросить обновление из вашего api.
Итак, что-то вроде
this._noteService.addNote(note).pipe(
concatMap(() => this._noteService.getNotesFromApi()))
.subscribe();
Это снова обновит вашу переменную notesData, которая находится в шаблоне.
Я надеюсь, вы понимаете, как работает этот поток, и если нет, не стесняйтесь спрашивать.
Надеюсь, это поможет!
Комментарии:
1. Итак, API написан на C #, и мы используем продукт ASP .NET Zero, в котором есть процесс, преобразующий C # в автоматически сгенерированный JS (Angular) в качестве сервисов. Таким образом, сервисы предварительно сгенерированы и передаются непосредственно в вызовы API. Возможно ли было бы выполнить первую 1/2 вашего ответа в notes.component.ts? Поток имеет полный смысл, я просто не могу изменить автоматически сгенерированный сервис-прокси, поскольку будущие изменения просто перезапишут файл.
2. Да, я имею в виду, что если у вас есть какие-то ограничения, то вам нужно настроить его на свой вкус. Я думаю, что в вашем сценарии наличие состояния внутри компонента также выполнило бы эту работу. Поскольку поток сохраняется, но разделения нет.
3. Решая эту проблему, я откорректировал ваш ответ и создал объект, подобный частному хранилищу данных, из которого я мог бы отправлять и извлекать данные и привязывать обратно к созданному нами observable, который извлекается из общедоступной переменной в качестве объекта async. Теперь все работает на удивление хорошо, и мне не нужно снова вручную обращаться к API, чтобы обновить компонент. Спасибо!