RxJS indexOfQuizId undefined in console - javascript

I've started refactoring my code to work with Angular Observables and I'm using the Observable 'of' for the quizzes$ array, but I'm stuck at getting indexOfQuizId working, specifically with findIndex. I am getting an undefined value for this.indexOfQuizId in the console, not sure what I'm doing wrong... Please could you see my code below (in getIndexOfQuizId()) and help to get it to work. Thank you!
In quiz.ts:
export const getQuizzes$: Observable<Quiz[]> = of([quiz data inside array]);
In quiz.service.ts:
export class QuizService {
quizzes$: Observable<Quiz[]>;
...
constructor(...) {
this.quizzes$ = getQuizzes$;
...
}
getQuizzes(): Observable<Quiz[]> {
return this.quizzes$;
}
getIndexOfQuizId() {
const index = this.getQuizzes().pipe(map(quizzes => {
this.indexOfQuizId = quizzes.findIndex((elem) => elem.quizId === this.quizId);
})).subscribe(x => {
console.log(x);
console.log('IOQID: ', this.indexOfQuizId);
});
}
In quiz.component.html, I'm using this.indexOfQuizId to access the quizzes$ array object like this:
this.totalQuestions = this.quizzes$[this.quizService.indexOfQuizId].questions.length;

You have an undefined for this line console.log('IOQID: ', this.indexOfQuizId); and it's quite right.
As you may know, the subscribe is asynchronous, that means that the next line (console.log('IOQID: ', this.indexOfQuizId);) is called before you set any value into this.indexOfQuizId since the map will be called eventually.
Try to move the console.log into the subscribe like this:
getIndexOfQuizId() {
const index = this.getQuizzes().pipe(map(quizzes => {
this.indexOfQuizId = quizzes.findIndex(function(elem, i, obs) { return elem => elem.quizId === this.quizId; });
})).subscribe(x => {
console.log(x);
console.log('IOQID: ', this.indexOfQuizId);
});
}

Related

Trouble with Addition Assignment in Array from Firebase

I have a scenario where i need to query multiple collections at once and retrieve the values based on the collection name. I use Promise.all to do so and it works accordingly like so
var dbPromises = [];
dbPromises.push(
admin.firestore().collection("collection1").where("user_id", "==", uid).get(),
admin.firestore().collection("collection2").where("user_id", "==", uid).get(),
admin.firestore().collection("collection3").where("user_id", "==", uid).get(),
);
const promiseConst = await Promise.all(dbPromises);
promiseConst.forEach((qs) => {
if (qs.size > 0) {
if (qs.query._queryOptions.collectionId == "collection1") {
qs.docs.map((doc) => {
valuesArr1.push(doc.data().arr);
});
} else if (qs.query._queryOptions.collectionId == "Collection2") {
qs.docs.map((doc) => {
valuesArr2.push(doc.data());
});
} else if (qs.query._queryOptions.collectionId == "collection3") {
qs.docs.map((doc) => {
valuesArr3.push(doc.data());
});
}
} else {
return
}
});
for (var i=0; i < valuesArr1.length; i++) {
if (valuesArr1[i].desiredData) {
console.log('datas from for loop on datas array', valuesArr1[i].desiredData)
globalVariable += `<img src="${valuesArr1[i].desiredData}">`;
}
}
Once I do this I map the query snapshot I get and am able to retrieve the values up to this point like so
From the first collection I retrieve an array from a firestore document and then the following collections i just retrieve all documents from the collections. This all 'works' in that when I console.log into the functions console the data shows up exactly as expected. It's only when I want to iterate over the data and assign the results to a global variable to use elsewhere that strange behavior occurs.
The console.log shows the desired data in the functions console with no issues, but the output when I interpolate that data into the html and send it off in nodemailer I get the following result
undefined is always the first in the response when i use the += addition assignment operator, but if i just use the = assignment operator there's no undefined but I obviously don't get all the data I'm expecting.
There are no undefined values or documents in the collections that I'm retrieving, I've checked thoroughly and even deleted documents to make sure of it. After days of researching I've come to the conclusion it has to do with the asynchronous nature of the promise I'm working with and the data not being immediately ready when I iterate it.
Can someone help me understand what I'm doing wrong and how to fix it in node?
I figured out a solution to my problem and would like to share it in hopes it saves a future viewer some time.
Before, I was storing the results of the array from Firebase inside a global variable. To save some head scratching I'll post the code again below.
var globalVariableArray = []
var globalVariable
var dbPromises = [];
dbPromises.push(
admin.firestore().collection("DataCollection").where("user_id", "==", uid).get()
);
const promiseConst = await Promise.all(dbPromises);
promiseConst.forEach((qs) => {
if (qs.size > 0) {
if (qs.query._queryOptions.collectionId == "DataCollection") {
Promise.all(
qs.docs.map(doc => {
globalVariableArray = doc.data().arrayWithDesiredData;
})
);
}
else {
return
}
});
globalVariableArray.map(gv => {
globalVariable += `<p>gv.desiredData</p>` // <--- Right here is where the problem area was
})
var mailOptions = {
from: foo#blurdybloop.com,
to: 'bar#blurdybloop.com
subject: 'Almost but not quite',
html: `${globalVariable}`
};
The above code give the expected output, but the output would always have undefined first before the data showed. This happened no matter how the array from Firebase was iterated over.
After strengthening my Google-Fu, I worked out the following solution
var globalVariableArray = []
var globalVariable
var dbPromises = [];
dbPromises.push(
admin.firestore().collection("DataCollection").where("user_id", "==", uid).get()
);
const promiseConst = await Promise.all(dbPromises);
promiseConst.forEach((qs) => {
if (qs.size > 0) {
if (qs.query._queryOptions.collectionId == "DataCollection") {
Promise.all(
qs.docs.map(doc => {
globalVariableArray = doc.data().arrayWithDesiredData;
})
);
}
else {
return
}
});
var mailOptions = {
from: foo#blurdybloop.com,
to: 'bar#blurdybloop.com
subject: 'It works!!',
html: `${globalVariableArray.map(dataIWantedAllAlong => <p>dataIWantedAllAlong.desiredData</p> )}` <--- Here I simply loop through the array inside the interpolation blocks and voila! no more undefined showing up in the results
};
I perform the loop inside the brackets where I interpolate the dynamic data and am no longer getting that pesky undefined showing up in my emails.
Safe travels and happy coding to you all!

Autodesk Forge: Viewer Extension cant use .getExternalIdMapping()

class IBSProgressExtension extends Autodesk.Viewing.Extension{
constructor(viewer, options) {
super(viewer, options);
}
load() {
//For proof of concept project, I will simply store the externalIds here in a variable.
const allExternalIds = [
'8a00f4c7-0709-4749-88b6-abb0ddccf965-0006879a',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-000688ee',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068961',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068963',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a78',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0d',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0f',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a11',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a13',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c2f',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c31',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c33',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b2e',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b30',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b32',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b34',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3e',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b36',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b38',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3a',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3c'
];
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
function onSuccessMapping(data) {
const resArray = [];
allExternalIds.forEach(externalId => {
if (data[externalId]) resArray.push(data[externalId], externalId);
});
console.log(resArray);
};
console.log('IBSProgressExtension is loaded.');
return true;
}
};
Autodesk.Viewing.theExtensionManager.registerExtension("IBSProgressExtension", IBSProgressExtension);
Please have a look at my extension and please help me figure out why is this happening.
Every time i run it, the devtools logs: ViewerExtension.js:31 Uncaught TypeError: Cannot read properties of undefined (reading 'getExternalIdMapping').
The extensions get loaded before the model so the getExternalIdMapping() method does not have the model properties yet. To handle this scenario, we usually recommend using the viewer events such as Autodesk.Viewing.GEOMETRY_LOADED_EVENT to “catch” the moment when the model is available. It’s better to wait for the event. This will be fired when the model/drawing finishes loading.
Instead of:
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
Try this:
this.viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, (x) => {
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
});
Please test this and see if it's helpful. I tried to incorporate items from your comments to help you structure it out.
class IBSProgressExtension extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super(viewer, options);
this._externalIds = null;
//Eventually will want to pass in your external IDs to this function, I assume:
//this._externalIds = options.externalIds
this._doStuff = () => {
this.startDoingStuff();
};
}
load() {
console.log("loading extension");
//For now, hard coded like your example.
this._externalIds = [
"8a00f4c7-0709-4749-88b6-abb0ddccf965-0006879a",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-000688ee",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068961",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068963",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a78",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0d",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0f",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a11",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a13",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c2f",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c31",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c33",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b2e",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b30",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b32",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b34",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3e",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b36",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b38",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3a",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3c",
];
//Not sure if this is truly the right event, but it worked when I tested on mine.
this.viewer.addEventListener(Autodesk.Viewing.MODEL_LAYERS_LOADED_EVENT, this._doStuff);
}
startDoingStuff() {
console.log("startDoingStuff executing");
this.getDbIds(this._externalIds).then((CombinedArray) => {
this.setCustomColors(CombinedArray);
});
}
setCustomColors(arrayOfIDs) {
console.log("setCustomColors executing");
var somecolor = "#7D5B51";
var threecolor = new THREE.Color(somecolor);
var vectcolor = new THREE.Vector4(threecolor.r, threecolor.g, threecolor.b, 1);
arrayOfIDs.forEach((e) => {
this.viewer.setThemingColor(e[0], vectcolor, this.viewer.getVisibleModels()[0]);
});
}
getDbIds(externalIds) {
console.log("getDbIds executing");
return new Promise((resolve) => {
this.viewer.model.getExternalIdMapping((d) => {
//console.log("getDbIdFromExternalId Executed");
let responseArr = [];
externalIds.forEach((externalId) => {
if (d[externalId]) responseArr.push([d[externalId], externalId]);
});
console.log("resolving", responseArr);
resolve(responseArr);
});
});
}
}
Autodesk.Viewing.theExtensionManager.registerExtension("IBSProgressExtension", IBSProgressExtension);
Regarding this, I was trying to achieve 3 things at this stage.
Get the externalIds from Mongodb.
Compare the externalIds with the ones gotten from getExternalIdMapping().
Get DbIds of those that matched.
Solved these by realising 2 and 3 can be put inside a.then() after .loadDocumentNode().

React - Array in state is defined, but Array[index] is undefined

I am writing a react app to fetch vocabulary from a backend database and then display it to the user, along with some information about each particular word. My problem is that I can't get the word to display inside render() as the index of the array is undefined, however according to chrome devtools the array is fully defined.
Here's my code:
import React from 'react';
import "./Vocab.css"
class Vocab extends React.Component {
//HEADER HEADER HEADER
state = {
vocabulary: null,
var2: null
};
componentDidMount(){
//Initializing Routine Here
this.getVocab()
}
getVocab = () => {
var newVocab = [];
if(this.state.vocabulary == null){
newVocab = newVocab;
}
else{
newVocab = [this.state.vocabulary];
}
this.props.HandleFetch("GET", this.props.backLink + "vocab")
.then(r => JSON.parse(r))
.then(data => newVocab.push(data[0]))
.then(this.setState({vocabulary:newVocab}))
}
//In render() variable display and the if/else statements are used exclusively for testing purposes
render() {
var display = "X";
if(this.state.vocabulary == null){
display = "Y";
}
else{
console.log(this.state.vocabulary); //Outputs the array
console.log(this.state.vocabulary[0]) //Outputs "undefined"
display = "Z";
}
return (
<>
<h1>Test</h1>
{display}
</>
);
}
}
export default Vocab;
The output of console.log(this.state.vocabulary):
0:
Definition: "TestDef"
IPA: "TestIPA"
IsCard: true
Language: "TestLang"
LastStudyDate: "2021-01-27"
Mnem: ""
PoS: "TestPO"
Source: "TestDict"
SourceLearned: "TestSource"
Word: "Test"
The output of this.state.vocabulary[0]:
undefined
Additionally, according to chrome devtools and through typing $r.state.vocabulary[0] in the console I get the dictionary at the array's index, which I need:
{Word: "Test", Mnem: "", LastStudyDate: "2021-01-27", SourceLearned: "TestSource", IsCard: true, …}
In the console the array is fully navigable, but the web page itself won't render it. Any idea what I might be doing wrong?
UPDATE
I was able to add a button the onClick goes to a function which prints out vocabulary and vocabulary[0]. This DOES work, but the render() function and componentDidUpdate() function still cannot access vocabulary[0]. I don't see anything in the react documentation that talks about a setState() finishing or any function happening after componentDidUpdate().
Additionally during some earlier testing I tried to console.log newVocab[0] before assigning it to state in a .then string. This worked, but outputted in the console only after all my other console calls, which indicates that it is happening after the component rerender and update cycle, even though I was calling it before I called setState().
My current test code so far:
import "./Vocab.css"
class Vocab extends React.Component {
//HEADER HEADER HEADER
state = {
vocabulary: null,
var2: null
};
componentDidMount(){
//Initializing Routine Here
this.getVocab()
}
componentDidUpdate(){
console.log("Vocab update");
console.log(this.state.vocabulary);
console.log("Vocab[0] update");
console.log(this.state.vocabulary[0]);
///Outputs the vocabulary array, and then 'undefined'
}
getVocab = () => {
var newVocab = [];
if(this.state.vocabulary == null){
newVocab = newVocab;
}
else{
newVocab = this.state.vocabulary;
}
this.props.HandleFetch("GET", this.props.backLink + "vocab")
.then(r => JSON.parse(r))
.then(data => newVocab.push(data[0]))
.then(this.setState({vocabulary:newVocab}))
}
logVocab = () => {
console.log("Vocab");
console.log(this.state.vocabulary);
console.log("Vocab[0]");
console.log(this.state.vocabulary[0]);
///Outputs the vocabulary array, and then the dictionary at index[0].
}
render() {
var display = "X";
if(this.state.vocabulary == null){
display = "Y";
console.log("Y");
}
else{
console.log("Vocab Z");
console.log(this.state.vocabulary);
console.log("Vocab[0] Z");
console.log(this.state.vocabulary[0]);
display = "Z";
///Outputs the vocabulary array, and then 'undefined'
}
return (
<>
<h1>Test</h1>
{this.state.vocabulary ? this.state.vocabulary[0] : ""}
<button onClick = {this.logVocab}> CLICK </button>
</>
);
}
}
export default Vocab;
The problem is the state.vocabulary is still null when you're trying to log out vocabulary[0]. Since this.props.HandleFetch is an async operation, you need to wait until this.state.vocabulary is set, like this:
render() {
const { vocabulary } = this.state;
if (!vocabulary) {
// render nothing if vocabulary is null
return null;
}
// This will log out the first element of vocabulary instead of undefined
console.log(this.state.vocabulary[0]);
return (
...
);
}
UPD: You also have incorrect syntax in getVocab method:
.then(this.setState({vocabulary:newVocab}))
What it does is immediately assign vocabulary to the newVocab variable which is an empty array at the moment of execution. Then, when this.props.HandleFetch gets fulfilled, newVocab is filled with response data.
You can fix this like the following:
this.props.HandleFetch("GET", this.props.backLink + "vocab")
.then(r => JSON.parse(r))
.then(data => this.setState({ vocabulary: data[0] }))
Update: I was able to track down the problem.
The issue was with the .then string. If you use .then but do not pass an argument to the code you want to execute, it looks like the .then portion will just be omitted and it will run without waiting, which is what was causing things to run out of order.
I believe the relevant line from the documentation (here) is
If one or both arguments are omitted or are provided non-functions, then then will be missing the handler(s), but will not generate any errors. If the Promise that then is called on adopts a state (fulfillment or rejection) for which then has no handler, the returned promise adopts the final state of the original Promise on which then was called.
My updated, and working, getVocab() function:
var newVocab = [];
if(this.state.vocabulary == null){
newVocab = newVocab;
}
else{
newVocab = this.state.vocabulary;
}
this.props.HandleFetch("GET", this.props.backLink + "vocab")
.then(r => JSON.parse(r))
.then(data => {newVocab.push(data[0]);
this.setState({vocabulary:newVocab})})
//Outputs correctly due to 'data' argument
}
Thank you to everyone who commented or helped me with this.

How to break the for loop using state

I have code as below.
I need to break the loop when first match is found.
const [isCodeValid, setIsCodeValid] = useState(false);
for (let i = 0; i < properyIds.length; i++) {
if (isCodeValid) {
break; // this breaks it but had to click twice so state would update
}
if (!isCodeValid) {
firestore().collection(`properties`)
.doc(`${properyIds[i]}`)
.collection('companies').get()
.then(companies => {
companies.forEach(company => {
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
console.log("should break here")
// updating state like this wont take effect right away
// it shows true on second time click. so user need to click twice right now.
setIsCodeValid(true);
}
});
})
}
}
state won't update right away so if (!isCodeValid) only works on second click.
Once I find match I need to update state or variable so I can break the for loop.
I tried to use a variable but its value also not changing in final if condition, I wonder what is the reason? can anyone please explain ?
You should try and rewrite your code such that you will always call setIsCodeValid(value) once. In your case it could be called multiple times and it might not get called at all
const [isCodeValid, setIsCodeValid] = useState(false);
function checkForValidCode() {
// map to an array of promises for companies[]
const companiesPromises = properyIds.map(propertyId =>
firestore()
.collection(`properties`)
.doc(propertyId)
.collection('companies').get())
Promise.all(companiesPromises)
// flatten the 2d array to single array, re-create to JS array because of firestores internal types?
.then(companiesArray => [...companiesArray].flatMap(v => v))
// go through all companies to find a match
.then(companies =>
companies.find(
company => _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())
))
.then(foundCompany => {
// code is valid if we found a matching company
setIsCodeValue(foundCompany !== undefined)
})
}
Try something like this:
import { useState } from 'react';
function YourComponent({ properyIds }) {
const [isCodeValid, setIsCodeValid] = useState(false);
async function handleSignupClick() {
if (isCodeValid) {
return;
}
for (let i = 0; i < properyIds.length; i++) {
const companies = await firestore()
.collection(`properties`)
.doc(`${properyIds[i]}`)
.collection('companies')
.get();
for (const company of companies.docs) {
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
setIsCodeValid(true);
return;
}
}
}
}
return (<button onClick={handleSignupClick}>Sign Up</button>);
}
If you await these checks, that will allow you to sequentially loop and break out with a simple return, something you can't do inside of a callback. Note that if this is doing database queries, you should probably show waiting feedback while this is taking place so the user knows that clicking did something.
Update:
You may want to do all these checks in parallel if feasible so the user doesn't have to wait. Depends on your situation. Here's how you'd do that.
async function handleSignupClick() {
if (isCodeValid) {
return;
}
const allCompanies = await Promise.all(
properyIds.map(id => firestore()
.collection(`properties`)
.doc(`${properyIds[i]}`)
.collection('companies')
.get()
)
);
setIsCodeValid(
allCompanies.some(companiesSnapshot =>
companiesSnapshot.docs.some(company =>
_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())
)
)
);
}
Can you not break it after setIsCodeValid(true);?
Use some:
companies.some(company => {
return _.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase());
});
If some and forEach are not available then companies is not an array but an array-like object. To iterate through those, we can use for of loop:
for (const company of companies){
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
// do something
break;
}
}
I tired below and it worked for me to break the loop.
I declared and tried to change this variable let codeValid and it was just not updating its value when match found. (not sure why)
But all of a sudden I tried and it just works.
I didnt change any actual code except for variable.
let codeValid = false;
let userInformation = []
for (let i = 0; i < properties.length; i++) {
console.log("called")
const companies = await firestore().collection(`properties`)
.doc(`${properties[i].id}`)
.collection('companies').get()
.then(companies => {
companies.forEach(company => {
if (_.trim(company.data().registrationCode) === _.trim(registrationCode.toUpperCase())) {
// a += 1;
codeValid = true;
userInformation.registrationCode = registrationCode.toUpperCase();
userInformation.companyName = company.data().companyName;
userInformation.propertyName = properties[i].propertyName;
}
});
})
if (codeValid) {
break;
}
}

How to know when real time update ends - Cloud Firestore ionic 4 with angular

I'm using cloud firestore for my DB, having no problems with read and writes. My issue is that i don't understand how to know when real time update has ended!
I'm using real time update as described in official cloud firestore documentation. It returns a function instead an observable. Now i'm not sure how to use it correctly.
I need to execute some code after data is loaded, but i have no subscribe((data) => {...}) to put it there!!
How to do it?
If i show lack of knowledge, please guide me to some documentation.
Thanks
This code is working fine and i'm using it directly on html like ListService.places$ to access data array.
public places$: BehaviorSubject<Array<Place>> = new BehaviorSubject<Array<Place>>([]);
private unsubscribe: Function;
public list(city: string, country: string) {
return this.unsubscribe = this.firestore.firestore.collection('places')
.where("location.country", "==", country)
.where("location.city", "==", city)
.orderBy("startDate", "desc")
.onSnapshot(querySnapshot => {
const list: Place[] = [];
if(!querySnapshot.docs.length) {
this.places$.next(list);
} else {
querySnapshot.docs.forEach(doc => {
let places = new Place();
place = doc.data() as Place;
places.push(place);
if(list.length === querySnapshot.docs.length) {
this.places$.next(list);
}
});
}
});
}
You need to subscribe to this.places$
this.places$.subscribe((data) => {
console.log(data);
});
What the real time function returns does not metter, because the real time function adds the output to the BehaviorSubject.
See here
let places = new Place();
place = doc.data() as Place;
places.push(place);
if(list.length === querySnapshot.docs.length) {
this.places$.next(list);
}
That means if you want to do something with the data you just need to subscribe to places$.
Also i think you have a small typo there, you never pushed values to the list array.
It should be something like:
...
.onSnapshot(querySnapshot => {
const list: Place[] = [];
if(!querySnapshot.docs.length) {
this.places$.next(list);
} else {
querySnapshot.docs.forEach(doc => {
let place = new Place();
place = doc.data() as Place;
list.push(place);
if(list.length === querySnapshot.docs.length) {
this.places$.next(list);
}
});
}
});

Categories

Resources