Я схожу с ума от следующей проблемы RxJS.
В классе обслуживания Angular у меня изначально был этот метод, извлекающий данные из базы данных Firebase FireStore:
async getAllEmployees() {
return <Observable<User[]>> this.firestore.collection('users',ref => ref.where('profileType', '!=', 'admin')).valueChanges();
}
возвращающий Observable, содержащий массив объектов User. Это прекрасно работает.
Этот метод службы вызывается методом кода компонента TypeScript, вот этот:
async loadEmployeesList() {
this.employeesList$ = await this.employeeService.getAllEmployees();
console.info("employeesList$: ", this.employeesList$);
}
Теперь у меня есть следующая проблема: я должен добавить вычисляемое поле к каждому объекту, полученному FireStore. Это поле имеет полное имя и является конкатенацией следующих двух полей: имя и фамилия.
Поэтому я попытался сделать это следующим образом, используя RxJS:
async getAllEmployees() {
//return <Observable<Employee[]>> this.firestore.collection('users',ref => ref.where('profileType', '!=', 'admin')).valueChanges();
return <Observable<Employee[]>> <unknown>this.firestore.collection('users', ref => ref.where('isEmployee', '==', true)).snapshotChanges()
.subscribe(snaps => {
snaps.map(snap => {
console.info("CURRENT SNAP: ", snap);
let currentEmployee: Employee = {
id: snap.payload.doc.id,
firstName: snap.payload.doc.get("firstName"),
surname: snap.payload.doc.get("surname"),
completeName: snap.payload.doc.get("firstName") + " " + snap.payload.doc.get("surname"),
placeOfBirth: snap.payload.doc.get("placeOfBirth"),
socialSecurityCode: snap.payload.doc.get("socialSecurityCode"),
birthDate: snap.payload.doc.get("birthDate"),
companyEmail: snap.payload.doc.get("companyEmail"),
personalEmail: snap.payload.doc.get("personalEmail"),
companyPhone: snap.payload.doc.get("companyPhone"),
personalPhone: snap.payload.doc.get("personalPhone"),
selectedEmployeeStatus: snap.payload.doc.get("selectedEmployeeStatus"),
isEmployee: snap.payload.doc.get("isEmployee"),
isAdmin: snap.payload.doc.get("isAdmin"),
};
console.info("currentEmployee: ", currentEmployee);
return currentEmployee;
});
});
}
Этот метод перебирает каждый объект Employee[] и извлекается из FireStore и добавляет следующие два поля к исходному объекту:
id: snap.payload.doc.id,
и
completeName: snap.payload.doc.get("firstName") + " " + snap.payload.doc.get("surname"),
возврат измененного объекта.
Теперь проблема в том, что мое приложение сломалось, и в консоли браузера я получаю это сообщение об ошибке:
ERROR Error: InvalidPipeArgument: '[object Object]' for pipe 'AsyncPipe'
at invalidPipeArgumentError (common.js:4154)
at AsyncPipe._selectStrategy (common.js:4256)
at AsyncPipe._subscribe (common.js:4246)
at AsyncPipe.transform (common.js:4234)
at Module.ɵɵpipeBind1 (core.js:24743)
at EmployeeListComponent_Template (employee-list.component.html:31)
at executeTemplate (core.js:7457)
at refreshView (core.js:7326)
at refreshComponent (core.js:8473)
at refreshChildComponents (core.js:7132)
Я думаю, что проблема связана с тем, что в компоненте Angular, который вызывает мой сервисный метод:
// Load the list of all the employees:
async loadEmployeesList() {
this.employeesList$ = await this.employeeService.getAllEmployees();
console.info("employeesList$: ", this.employeesList$);
}
Я больше не получаю Observable, но получаю объект Subscriber (я вижу его с помощью console.info())
Как я могу исправить свой код, чтобы вернуть Observable, содержащий массив с измененными объектами?
Подписка на поток возвращает его подписку.
const stream = of(1,2,3,4);
const subscription = stream.subscribe();
Вы подписываетесь, а затем возвращаете эту подписку
return stream.subscribe();
Похоже, что вы хотите сделать, это сопоставить каждый элемент в вашем потоке с новым элементом. Если это так, вы не должны subscribe
, вы должны observable#map
.
Что меня удивляет, так это то, что в вашем последнем вопросе вы действительно сделали map
свое userObject
, поэтому я не уверен, что послужило причиной изменения здесь при отображении массива.
Точно такой же подход работает, только теперь вы отображаете массив, а не объект. map(array => array.map(...))
довольно часто встречается в RxJS.
getAllEmployees(): Observable<Employee[]> {
//return <Observable<Employee[]>> this.firestore.collection('users',ref => ref.where('profileType', '!=', 'admin')).valueChanges();
return <Observable<Employee[]>> <unknown>this.firestore.collection(
'users',
ref => ref.where('isEmployee', '==', true)
).snapshotChanges().pipe(
map(snaps =>
snaps
.map(snap => snap.payload.doc)
.map(doc => ({
id: doc.id,
firstName: doc.get("firstName"),
surname: doc.get("surname"),
completeName: `${doc.get("firstName")} ${doc.get("surname")}`,
placeOfBirth: doc.get("placeOfBirth"),
socialSecurityCode: doc.get("socialSecurityCode"),
birthDate: doc.get("birthDate"),
companyEmail: doc.get("companyEmail"),
personalEmail: doc.get("personalEmail"),
companyPhone: doc.get("companyPhone"),
personalPhone: doc.get("personalPhone"),
selectedEmployeeStatus: doc.get("selectedEmployeeStatus"),
isEmployee: doc.get("isEmployee"),
isAdmin: doc.get("isAdmin")
}))
)
);
}