I have a getProgrammeWrapper method that returns a promise. However in .then method i have few other promises that i will like to execute before returning the programmeWrapper[]
This is service.ts
I am calling the service in ngOnInit
this.service.getProgrammesByWrapper().then(((res) => {
this.programmes = res;
this.result.updateInfo("Sorting classes...")
this.programmes =this.programmes.sort((a,b) => {
return b.programme.click - a.programme.click;
});
this.result.updateSuccess(true);
}));
I hope i have explained the issue clearly. I have tried using await, but it doesn't work as expected.
getProgrammeWrapper()
getProgrammesByWrapper(): Promise<ProgrammeWrapper[]> {
var current = this;
var programmesDTO = new Array<ProgrammeWrapper>();
var table = this.client.getTable("programme");
return new Promise((resolve, reject) => {
table.read()
.then(function (modules) {
modules.forEach(element => {
var newProgDTO = new ProgrammeWrapper(element);
current.getLessonsByProgrammeId(element.id).then(lessons => newProgDTO.lesson = lessons).catch(err => console.log(err));
current.getUser(element.tutorId).then(user => newProgDTO.tutor = user).catch(err => console.log(err));
programmesDTO.push(newProgDTO)
});
resolve(programmesDTO)
}, function (error) { reject(error) });
});
}
I'm not sure it would work, could have bugs too. Try this:
getProgrammesByWrapper(): Promise<ProgrammeWrapper[]> {
var current = this;
var programmesDTO = new Array<ProgrammeWrapper>();
var table = this.client.getTable("programme");
return new Promise((resolve, reject) => {
table.read()
.then(function (modules) {
let promises = new Array<Promise<any>>();
modules.forEach(element => {
var newProgDTO = new ProgrammeWrapper(element);
let promise = current.getLessonsByProgrammeId(element.id)
.then(lessons => newProgDTO.lesson = lessons)
.catch(err => console.log(err));
promises.push(promise);
promise = current.getUser(element.tutorId)
.then(user => newProgDTO.tutor = user)
.catch(err => console.log(err));
promises.push(promise);
programmesDTO.push(newProgDTO)
});
// Wait for all promises to be ready before resolving
Promise.all(promises).then(function() {
resolve(programmesDTO);
});
}, function (error) { reject(error); });
});
}
Related
I have a firestore collection containing post documents, each document contains a reference to an author (user) and a case document.
How do I get the user and the case in the same onSnapshot?
Here's what I'd like to do with await, but that doesn't seem to be an option with react-native-firebase.
export const firebasePostLooper = (snapshot) => {
let data = [];
snapshot.forEach(async (doc) => {
let newItem = {id: doc.id, ...doc.data()};
if (newItem.author) {
let authorData = await getDoc(newItem.author); // doesn't work with rnfirebase
if (authorData.exists()) {
newItem.userData = {userID: authorData.id, ...authorData.data()};
}
}
if (newItem.case) {
let caseData = await getDoc(newItem.case);
if (caseData.exists()) {
newItem.userData = {userID: caseData.id, ...caseData.data()};
}
}
data.push(newItem);
});
return data;
};
This doesn't work because getDoc() doesn't exist.
So I'm left with using .then()
export const firebasePostLooper = (snapshot) => {
let data = [];
snapshot.forEach((doc) => {
let newItem = {id: doc.id, ...doc.data()};
if (newItem.author) {
newItem.author
.get()
.then((res) => {
newItem.authorData = res.data();
if (newItem.case) {
newItem.case
.get()
.then((caseRes) => {
newItem.caseData = caseRes.data();
data.push(newItem);
})
.catch((err) => console.error(err));
}
})
.catch((err) => console.error(err));
} else {
data.push(newItem);
}
});
return data;
};
This second method doesn't seem to be working, data is empty at the return statement but data.push(newItem) contains the correct document with the 2 referenced documents.
You're returning data before it gets filled inside the promise. You should handle the returning of the data inside a .then() in order to return it after the promise has resolved and not before.
Take a look at this example where if we handle the emptyData object outside the promise chain, we just return the initial value before it has been filled.
let promise = new Promise((resolve, reject)=>{
setTimeout(resolve, 1000, 'foo');
})
let emptyData= [];
let notEmptyData = [];
promise
.then(res=>{
emptyData.push(res);
notEmptyData.push(res);
console.log("Full data: " + notEmptyData) // "Full data: foo"
});
console.log("Empty data: " + emptyData); // "Empty data: "
I have a function that create tasks and writing it in firebase real time database.
export const createNewTask = (task) => new Promise(async (resolve, reject) => {
try {
await database().ref('tasks').child(auth().currentUser.uid).child(task.taskCreationDate.toString()).set(task);
resolve();
} catch (e) {
reject(e);
}
});
And it's working good :
Now, I have a socond functions that should read that tasks.
export const fetchTasks = () => (dispatch) => new Promise(async (resolve, reject) => {
try {
const snapshot = await database().ref('tasks').child(auth().currentUser.uid).once('value');
if (snapshot.exists) {
const tasks = snapshot.val();
dispatch({
type: FETCH_TASKS,
payload: tasks,
});
resolve(tasks);
} else {
resolve(snapshot);
}
} catch (e) {
reject(e);
}
});
And here is the problem:
When I'm using useSelector in my home screen const tasks = useSelector(state => state.GeneralReducer.taskList);
The tasks list is undefiend.
When I used mock data with same objects , it's work fine.
How can I get a list of task?
Ok , fixed it by adding :
Object.keys(data).map(key => ({...data[key], id: key}));
to the function fetchTasks.
export const fetchTasks = () => (dispatch) => new Promise(async (resolve, reject) => {
try {
const snapshot = await database().ref('tasks').child(auth().currentUser.uid).once('value');
if (snapshot.exists) {
const data = snapshot.val();
const tasks = Object.keys(data).map(key => ({...data[key], id: key}));
dispatch({
type: FETCH_TASKS,
payload: tasks,
});
resolve(tasks);
} else {
resolve(snapshot);
}
} catch (e) {
reject(e);
}
});
I've been working on getting a custom tab working in MS teams using MSAL. I've been following the example here: https://github.com/nmetulev/teams-msal and I can generate a token. I then try to forward this token to my API, where I build a security claim and call SignInAsync() to persist the cookie.
This then gets stored, and I forward to my standard page, but this does not page auth (I get unauthorized). Is there something I'm missing that I need to be doing?
Auth Page
const signIn = () => {
msalApp.acquireTokenRedirect(authenticationParameters);
}
const handleSignedIn = () => {
microsoftTeams.initialize();
microsoftTeams.authentication.notifySuccess();
}
const handleSignedOut = (error) => {
microsoftTeams.initialize();
microsoftTeams.authentication.notifyFailure(error);
}
const handleErrorReceived = (authError, accountState) => {
console.log(authError, accountState);
handleSignedOut({authError});
}
const handleTokenReceived = (response) => {
console.log(response);
handleSignedIn();
}
// MAIN
const msalApp = new Msal.UserAgentApplication(msalConfig);
msalApp.handleRedirectCallback((response) => handleTokenReceived(response), (error, state) => handleErrorReceived(error, state));
microsoftTeams.initialize();
microsoftTeams.getContext((context) => {
authenticationParameters = {
scopes: scopes,
loginHint: context.loginHint
};
setTimeout(() => {
attemptSilentSignIn().then(success => {
if (success) {
handleSignedIn();
} else {
signIn();
}
});
},
4000);
});
Sign In Page:
const attemptSilentSignIn = () => {
renderLoading();
if (msalApp.getAccount()) {
msalApp.acquireTokenSilent({ scopes }).then((response) => {
if (response && response.accessToken) {
handleSignedIn(response.accessToken);
} else {
handleSignedOut();
}
}, () => {
handleSignedOut();
})
} else {
handleSignedOut();
}
}
const signIn = () => {
renderLoading();
microsoftTeams.initialize(() => {
microsoftTeams.authentication.authenticate({
url: window.location.origin + "/resources/TeamsAuthFlow.html",
successCallback: () => attemptSilentSignIn(),
failureCallback: (error) => renderError(error)
});
});
}
const handleSignedIn = (accessToken) => {
microsoftTeams.initialize();
microsoftTeams.getContext((context) => {
var tenant = $("<input>").attr("id", "TenantId").attr("name", "TenantId").val(context.tid);
var token = $("<input>").attr("id", "AuthToken").attr("name", "AuthToken").val(accessToken);
var form = $("<form>").css("display", "none").attr("id", "target").attr("method", "POST").attr("action", "/api/TeamsTabSignIn").append(tenant).append(token).submit();
$("body").append(form);
$("#target").submit();
});
}
const handleSignedOut = () => {
renderSignedOutView();
}
// MAIN
let app = document.querySelector('.app');
const msalApp = new Msal.UserAgentApplication(msalConfig);
attemptSilentSignIn();
let authenticationParameters = null;
const handleErrorReceived = (authError, accountState) => {
console.log(authError, accountState);
handleSignedOut({ authError });
}
const handleTokenReceived = (response) => {
console.log(response);
handleSignedIn();
}
API Call
TenantId = Context.Request.Form["TenantId"];
AuthToken = Context.Request.Form["AuthToken"];
var principal = await _authHelper.SetPlatformUser(TenantId, AuthToken);
if (principal is ClaimsPrincipal cp)
{
await Context.SignInAsync("Cookies", cp, new AuthenticationProperties { IsPersistent = true });
Response.Redirect("/app/teamspage/Ticket");
}
I am trying to get data from Firebase realtime database in the loop and set array items,
but just the last item can set.
it's looking like synchronize problems I tried a lot of things but couldn't solve it.
import FireBaseConnection from '../classes/firebaseconnection.js';
const getComments = () => {
let cardatafetch=[]
FireBaseConnection.GetData('/PostComments/1234').then((comments) => {
for (i in comments) {
cardatafetch.push(comment[i])
}
for (j in cardatafetch) {
var UserId = cardatafetch[j]["UserID"]
FireBaseConnection.GetData('/Users/'+UserId).then((user) => {
cardatafetch[j].ProfilePicture=user["ProfilePicture"]
})
.catch((error) => {
console.log(error)
});
}
console.log(cardatafetch)
}).catch((error) => {
console.log(error)
});
}
}
Console Output is
Same problem also during get images from storage
for (j in cardatafetch) {
FireBaseConnection.GetImage().then((obj) => {
cardatafetch[j].ProfilePicture=obj
})
.catch((error) => {
console.log(error)
});
}
FireBaseConnection Class
import database from '#react-native-firebase/database';
import storage from '#react-native-firebase/storage';
import { utils } from '#react-native-firebase/app';
class FireBaseConnection
{
static async GetData(refValue) {
let data;
await database()
.ref(refValue)
.once('value')
.then(snapshot => {
data = snapshot.val();
});
return data;
}
static async GetImage(imgValue) {
const reference = storage().ref(imgValue);
let imagePath= await reference.getDownloadURL().then(result =>result);
return imagePath;
}
}
export default FireBaseConnection;
Try below code, what I have done is put your code inside last iteration of the loop so it will be implemented only once when all the items are pushed in the array.
import FireBaseConnection from '../classes/firebaseconnection.js';
const getComments = () => {
return new Promise((resolve, reject) => {
let commentsArr = [];
FireBaseConnection.GetData('/PostComments/1234').then((comments) => {
Object.keys(comments).forEach((key, index) => {
commentsArr.push(comments[key])
if(index == Object.keys(comments).length-1) {
resolve(commentsArr);
}
});
}).catch((error) => {
console.log(error)
});
});
}
const addImagesToComment = () => {
this.getComments().then((comments) => {
var finalArr = [];
comments.forEach((comment, index) => {
var tempComment = comment;
var UserId = comment["UserID"]
FireBaseConnection.GetData('/Users/' + UserId).then((user) => {
tempComment.ProfilePicture = user["ProfilePicture"]
finalArr.push(tempComment);
}).catch((error) => {
console.log(error)
});
if(index == comments.length-1) {
console.log(finalArr)
}
});
});
}
Try calling getComments function.
i have a skill and i want to load some data from an url and store it in the SessionAttributes.
so i wrote this into my handle(handlerInput)of my LaunchRequestHandler:
require('https').get(url, (resp) => {
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
let attributes = JSON.parse(data);
console.log(attributes);
handlerInput.attributesManager.setSessionAttributes(attributes);
});
});
the log shows me the correct object, but when i try to load the sessionAttributes in the next intent it's empty. I Assume it has something to do with the setSessionAttributes being in the response function, because if i set something directly after this code, it works. Any ideas?
This might be because of the asynchronous operation. Please use async/await to make the API call and then save. Sample example,
const getData = () => {
return new Promise((resolve, reject) => {
require("https").get(url, resp => {
resp.on("data", chunk => {
data += chunk;
});
resp.on("end", () => {
resolve(data);
});
});
});
};
const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === "LaunchRequest";
},
async handle(handlerInput) {
const speechText = "welcome";
const data = await getData(); //asynchronous operation
const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
sessionAttributes.data = data;
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard("Welcome to the Skill", speechText)
.getResponse();
}
};