#angular #firebase #google-cloud-firestore #rxjs #firebase-storage
#angular #firebase #google-cloud-firestore #rxjs #firebase-хранилище
Вопрос:
Я не очень разбираюсь в Angular и Firebase, и у меня следующая проблема.
У меня есть следующий код, который обрабатывает весь цикл регистрации пользователя. Это частично работает, но у меня есть проблема, которую я попытаюсь подробно объяснить (вероятно, потому, что у меня все еще есть некоторые трудности с функциональным программированием …):
createUser(user, file) {
console.log(user);
if(user.password != user.password_confirmation) {
let passwordError: any = new Object();
passwordError["message"] = "Inserted password and inserted password confirmation are different";
this.eventAuthError.next(passwordError);
}
else {
this.afAuth.auth.createUserWithEmailAndPassword(user.email, user.password)
.then( userCredential => {
this.newUser = user;
console.log(userCredential);
userCredential.user.updateProfile( {
displayName: user.firstName ' ' user.lastName
});
this.uploadFileIntoFirebaseStore(file);
this.insertUserData(userCredential, this.downloadURL)
.then(() => {
this.router.navigate(['/home']);
});
})
.catch( error => {
console.log(error);
console.log(typeof error);
this.eventAuthError.next(error); // Emit the event passing the error object
});
}
}
uploadFileIntoFirebaseStore(fileToBeUploaded) {
var n = Date.now();
const filePath = `user_avatar/${n}`;
const fileRef = this.storage.ref(filePath);
const task = this.storage.upload(`user_avatar/${n}`, fileToBeUploaded);
task
.snapshotChanges()
.pipe(
finalize(() => {
this.downloadURL = fileRef.getDownloadURL();
this.downloadURL.subscribe(url => {
if (url) {
this.fb = url;
}
console.log(this.fb);
});
})
)
.subscribe(url => {
if (url) {
console.log(url);
}
});
return this.fb
}
insertUserData(userCredential: firebase.auth.UserCredential, userAvatar) {
let userObg = {
name: this.newUser.firstName,
surname: this.newUser.lastName,
complete_name: this.newUser.firstName " " this.newUser.lastName,
email: this.newUser.email,
role: this.newUser.ruolo_utente,
avatar: userAvatar
};
console.log("USER OBJECT: ", userObg);
return this.db.doc(`Users/${userCredential.user.uid}`).set(userObg);
}
В основном он выполняет следующие действия:
-
createUser()
Возьмите пользовательский объект, который должен быть сохранен в коллекции FireStore, и параметр файла, который представляет собой изображение, которое должно быть сохранено в хранилище Firebase. -
Сначала он вызывает
createUserWithEmailAndPassword()
, который создает нового пользователя в службе аутентификации Firebase, используя имя пользователя и пароль (все работает нормально). -
Если пользователь создан правильно, он вводится в then() и вызывает
uploadFileIntoFirebaseStore()
метод, который используется для загрузки файла изображения в хранилище Firebase. -
Затем он вызывает
insertUserData()
метод, который создает и сохраняет новый объект, связанный с текущим пользователем, в FireStore.
Моя проблема возникает между точками 3 и 4. В деталях файл правильно сохраняется в хранилище Firebase, но мне кажется, что это асинхронная задача, и поэтому требуется некоторое время, прежде чем вернуть URL-адрес, связанный с этим файлом, в хранилище Firebase. Это занимает время, но тем временем insertUserData()
запускается, поэтому здесь это поле URL (которое я должен сохранить в своем объекте) не определено.
Какой может быть разумный способ подождать, пока URL-адрес файла не будет «возвращен»? Возможно, мне не нужно ничего возвращать, но было бы неплохо поместить вызов insertUserData()
(который вставляется в FireStore) в uploadFileIntoFirebaseStore()
метод после получения URL-адреса, здесь:
this.downloadURL.subscribe(url => {
if (url) {
this.fb = url;
// I PUT THE CALL TO HERE
}
console.log(this.fb);
});
Что может быть разумным решением этой проблемы?
Комментарии:
1. Для такого кода очень полезно, если вы изучите синтаксис JavaScript / TypeScript async / await, поскольку это значительно упрощает работу с сериями обещаний.
Ответ №1:
Вам нужны .pipe()
ваши потоки, иначе вы никогда не сможете их синхронизировать.
uploadFileIntoFirebaseStore
должен return
ли поток загрузки:
return this.storage.upload(`user_avatar/${n}`, fileToBeUploaded)
.snapshotChanges()
.pipe(switchMap(() => fileRef.getDownloadURL());
Затем в вашем createUser
вы можете использовать его:
this.uploadFileIntoFirebaseStore(file).subscribe(downloadURL =>
this.insertUserData(userCredential, downloadURL)
.then(() => {
this.router.navigate(['/home']);
});
);