I am trying to return the correct count of messages (length of listMessage) from the function below. I can retrieve correct message Objects into listMessage, but its length is always zero.
checkLastMsg = () =>
{
var groupChatId = null;
var listMessage = [];
// console.log(this.peerUserId);
if (this.hashString(this.currentUserId) <= this.peerUserId)
{
groupChatId = `${this.currentUserId}-${this.peerUserId}`;
}
else
{
groupChatId = `${this.peerUserId}-${this.currentUserId}`;
}
// console.log(groupChatId);
myFirestore
.collection(AppString.NODE_MESSAGES)
.doc(groupChatId)
.collection(groupChatId)
.onSnapshot(
snapshot =>
{
snapshot.docChanges().forEach(change =>
{
if (change.type === AppString.DOC_ADDED)
{
listMessage.push(change.doc.data())
}
})
},
err =>
{
this.props.showToast(0, err.toString())
})
// console.log(listMessage.length);
console.log(listMessage.length);
}
Could anyone check if something is wrong here and how I can fix this issue?
Like everybody said, the code is asynchronous, hence you can make work like this:
checkLastMsg = async () =>
{
var groupChatId = null;
var listMessage = [];
// console.log(this.peerUserId);
if (this.hashString(this.currentUserId) <= this.peerUserId)
{
groupChatId = `${this.currentUserId}-${this.peerUserId}`;
}
else
{
groupChatId = `${this.peerUserId}-${this.currentUserId}`;
}
// console.log(groupChatId);
await myFirestore
.collection(AppString.NODE_MESSAGES)
.doc(groupChatId)
.collection(groupChatId)
.onSnapshot(
snapshot =>
{
snapshot.docChanges().forEach(change => {
if (change.type === AppString.DOC_ADDED) {
listMessage.push(change.doc.data())
}
})
},
err => {
this.props.showToast(0, err.toString())
}
)
// console.log(listMessage.length);
console.log(listMessage.length);
}```
The Firebase code running asynchronously. Try to maybe log the list in the callback function or something like that
Related
Hi im working on a Chrome extension that adds badges to users, now the problem is i have to refresh the page everytime so the badges can load because there are client-side changes . How can i watch events change so i run the function on first time page load ?
I read something about input event listener or MutationObserver but im not sure how can i implement that , Any help would be much appreciated .
CODE:
function Foreground() {
let users = null;
let queries = [];
let userIds = [];
document.addEventListener("DOMContentLoaded", function(event) {});
window.addEventListener('load', () => {
fetchUsersAndQueries();
chrome.runtime.onMessage.addListener(async(message, sender, res) => {
if (message.users) {
fetchUsersAndQueries();
if (users) {
return res(users);
} else {
return res([]);
}
}
if (message.refresh) {
try {
assignBadges();
} catch (error) {
console.log(error.message);
}
}
return true;
});
let done = false;
setInterval(() => {
if (done) {
return;
}
if (users) {
done = true;
try {
assignBadges();
} catch (error) {
console.log(error.message);
}
}
}, 500);
});
async function fetchUsersAndQueries() {
userIds = await getAPIUserIds();
let isStop = false;
setInterval(() => {
if (isStop) {
return;
}
const parasiteContainer = document.querySelector('#parasite-container');
if (parasiteContainer) {
if (parasiteContainer.shadowRoot) {
try {
const roster1 = parasiteContainer.shadowRoot.querySelector(`[name="roster1"]`);
const roster2 = parasiteContainer.shadowRoot.querySelector(`[name="roster2"]`);
if (!roster1) {
return
};
if ([...roster1.children].length === 1) {
if (roster1.firstElementChild.children.length === 1) {
if (roster1.firstElementChild.firstElementChild.length === 1) {
const fTeam = [...roster1.firstElementChild.firstElementChild.firstElementChild.children].map(item => getUsername(item));
const sTeam = [...roster2.firstElementChild.firstElementChild.firstElementChild.children].map(item => getUsername(item));
users = fTeam.concat(sTeam).flat();
queries.push([...roster1.firstElementChild.firstElementChild.firstElementChild.children]);
queries.push([...roster2.firstElementChild.firstElementChild.firstElementChild.children]);
isStop = true;
} else {
const fTeam = [...roster1.firstElementChild.firstElementChild.children].map(item => getUsername(item));
const sTeam = [...roster2.firstElementChild.firstElementChild.children].map(item => getUsername(item));
users = fTeam.concat(sTeam).flat();
queries.push([...roster1.firstElementChild.firstElementChild.children]);
queries.push([...roster2.firstElementChild.firstElementChild.children]);
isStop = true;
}
} else {
const fTeam = [...roster1.firstElementChild.children].map(item => getUsername(item));
const sTeam = [...roster2.firstElementChild.children].map(item => getUsername(item));
users = fTeam.concat(sTeam).flat();
queries.push([...roster1.firstElementChild.children]);
queries.push([...roster2.firstElementChild.children]);
isStop = true;
}
}
queries.forEach(query => {
query.map(item => {
if (item.children.length > 1) {
[...item.children].map(child => {
// const container = child.querySelector('.sc-hCQDas'); // Classname might change in the future.
const container = child.firstElementChild ? .firstElementChild ? .firstElementChild ? .firstElementChild ? .children[2];
if (container) {
container.insertAdjacentHTML(
'beforeend',
createBadge(badgesResponse.data.exists, child.dataset.userId)
);
}
});
} else {
// const container = item.querySelector('.sc-hCQDas'); // Classname might change in the future.
const container = item.firstElementChild ? .firstElementChild ? .firstElementChild ? .children[0];
if (container) {
container.insertAdjacentHTML(
'beforeend',
createBadge(badgesResponse.data.exists, item.dataset.userId)
);
}
}
});
});
}
How could I improve this method of rendering only when both variables are met as true, to allow the renderFilters() method to be called:
These two variables are filled asynchronously through 2 API methods:
//getManager()
this.isLoadingManager = true;
//getPdiPOrganization()
this.isLoadingPdiOrganization = true;
promiseRender() {
let interval = setInterval(() => {
if (this.isLoadingManager && this.isLoadingPdiOrganization) {
clearInterval(interval);
this.renderFilters();
} else {
setTimeout(() => {
clearInterval(interval);
this.renderFilters();
}, 5000)
}
}, 500);
}
The problem is that it's very slow... it's calling long after the APIs are called...
Maybe some feature of angular itself, if anyone has a better solution...
const observable = forkJoin({
loading1:this.isLoadingManager,
loading2:this.isLoadingPdiOrganization
});
observable.subscribe({
next: (results) => {
const obs1Val = results[0];
const obs2Val = results[1];
if (obs1Val && obs2Val) {
this.renderFilters();
}
}
})
Or:
const myObservable = Observable.of(this.isLoadingManager && this.isLoadingPdiOrganization);
const myObserver = {
next: (result: Boolean) => this.renderFilters(),
};
myObserver.next(true);
myObservable.subscribe(myObserver);
Adding the methods:
getManager() {
if (this.fromAdminPage && localStorage.getItem('_receivers_pdi')) {
this.meetingService.getIsManager()
.subscribe(res => {
this.showPdiToastNotification = res;
this.isLoadingManager = true;
});
}
}
getPdiPOrganization() {
const url = this.publicEndpoint ? 'current/organization/pdi/configuration' : 'api/current/organization/pdi/configuration';
const requestOptions = {
params: new CustomHttpParams({ isPublicTokenUrl: this.publicEndpoint })
};
this.http.get<any>(url, requestOptions).subscribe(resp => {
this.isLoadingPdiOrganization = true;
this.pdiOrgConfig = resp || {};
this.updatePdiReferenceType(this.pdiOrgConfig);
});
}
You can use forkjoin to subscribe to two observables at the same time. I would stick with using RxJs operators for cases like these. You can read more about forkJoin here.
forkJoin([obs1, obs2]).subscribe({
next: (results) => {
const obs1Val = results[0];
const obs2Val = results[1];
if (obs1Val && obs2Val) {
this.renderFilters();
}
}
});
I'm trying to build a citation generator from json in an API with data about images, stored in key-value pairs. I can get the data to return to the screen, but it always includes undefined in the citation. Sample manifest returns undefined as the creator since that isn't listed in this particular record. How can I keep any undefined value from being returned? I've tried changing the forEach to map, filtering at allMetadata by string length, using if !== undefined at insertCitation, and versions of those in different spots in the code.
EDIT: updated to provide full code, including print to page
(function () {
'use strict';
const buildCitation = {
buildMetadataObject: async function (collAlias, itemID) {
let response = await fetch('/iiif/info/' + collAlias + '/' + itemID + '/manifest.json');
let data = await response.json()
let allMetadata = data.metadata
let citationData = {};
allMetadata.forEach(function (kvpair) {
if (kvpair.value == undefined) {
return false;
} else if (kvpair.label === 'Title') {
citationData.itemTitle = kvpair.value;
} else if (kvpair.label === 'Creator') {
citationData.itemCreator = kvpair.value;
} else if (kvpair.label === 'Repository') {
citationData.itemRepository = kvpair.value;
} else if (kvpair.label === 'Collection Name') {
citationData.itemCollection = kvpair.value;
} else if (kvpair.label === 'Owning Institution') {
citationData.itemOwning = kvpair.value;
} else if (kvpair.label === 'Date') {
citationData.itemDate = kvpair.value;
} else if (kvpair.label === 'Storage Location') {
citationData.itemStorage = kvpair.value;
}
return true;
});
return citationData;
},
insertCitation: function (data) {
var testTitle = data.itemTitle;
console.log(testTitle);
const itemCite = `Citation: "${data.itemTitle}," ${data.itemDate}, ${data.itemCreator}, ${data.itemCollection}, ${data.itemOwning}, ${data.itemStorage}, ${data.itemRepository}.`;
const citationContainer = document.createElement('div');
citationContainer.id = 'citation';
citationContainer.innerHTML = itemCite;
// CHANGED to innerHTML instead of innerText because you may want to format it at some point as HTML code.
if (testTitle) {
document.querySelector('.ItemView-itemViewContainer').appendChild(citationContainer);
}
}
}
document.addEventListener('cdm-item-page:ready', async function (e) {
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
document.addEventListener('cdm-item-page:update', async function (e) {
document.getElementById('citation').remove();
const citationData = await buildCitation.buildMetadataObject(e.detail.collectionId, e.detail.itemId);
console.log({ citationData });
buildCitation.insertCitation(citationData);
});
})();
I've simplified your program. The undefined is coming from the fact that there is no item with label Date
const mappings = {
Date: 'itemDate',
Title: 'itemTitle',
Creator: 'itemCreator',
Repository: 'itemRepository',
'Storage Location': 'itemStorage',
'Owning Institution': 'itemOwning',
'Collection Name': 'itemCollection',
}
async function buildMetadataObject(collAlias, itemID) {
let response = await fetch('https://teva.contentdm.oclc.org/iiif/info/p15138coll25/1421/manifest.json');
let data = await response.json()
return data.metadata.reduce(
(acc, { label, value }) => ({ ...acc, [ mappings[label] ]: value }),
{}
)
}
function insertCitation(data) {
var testTitle = data.itemTitle;
const fieldBlackList = ['itemTitle'];
const itemCite = `Citation: "${data.itemTitle}," ${
Object.values(mappings).reduce((acc, cur) => {
if (fieldBlackList.includes(cur)) return acc;
const value = data[cur];
return value ? [...acc, value] : acc
}, []).join(', ')
}.`;
console.log(itemCite);
}
//MAIN PROGRAM
(async() => {
const citationData = await buildMetadataObject();
insertCitation(citationData);
})()
I have a list of objects, and I wanted to filter it based on a specific string property.
openTasks: Task[]; //Initial list
inProgressTasks: Task[] = []; //Filtered list
getTasks(): void {
this.activatedRoute.paramMap.subscribe(params => {
this.projectId = +params.get('projectId');
if (this.projectId === 0) {
this.taskService.getTasks().subscribe(tasks => this.openTasks = tasks);
// HERE I ACQUIRE LIST OF OPEN TASKS
} else {
this.taskService.getTaskByProjectId(this.projectId).subscribe(tasks => this.openTasks = tasks);
// HERE I ACQUIRE LIST OF OPEN TASKS
}
// FILTER
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
});
}
I received this error:
ERROR TypeError: Cannot read property 'filter' of undefined
Could you, please, help me with this error?
Your probably having problems here because of the async nature with which you fetch openTasks.
Try waiting for it to definitely finish before trying to filter it.
getTasks(): void {
this.activatedRoute.paramMap.subscribe(params => {
this.projectId = +params.get('projectId');
if (this.projectId === 0) {
this.taskService.getTasks().subscribe(tasks =>
{this.openTasks = tasks},
error => {},
() => { this.filterTasks()}
);
}
});
}
filterTasks() {
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
}
The this.openTasks is not set yet. it is only set after the this.openTasks = tasks in subscribe. this should work.
this.activatedRoute.paramMap.subscribe(params => {
this.projectId = +params.get('projectId');
if (this.projectId === 0) {
this.taskService.getTasks()
.subscribe(tasks => {
this.openTasks = tasks;
// your code that requirest openTasks
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
});
} else {
this.taskService.getTaskByProjectId(this.projectId)
.subscribe(tasks => {
this.openTasks = tasks
// your code that requirest openTasks
this.inProgressTasks = this.openTasks.filter(task => task.state === 'IN_PROGRESS');
});
}
});
Hi i want to return the promise that gets resolved when the first poll finishes...
I have a start_polling method and i want to modify it such that it returns a promise that gets resolved when the items_promise gets resolved...i am not sure how to do it.
What i have tried?
i have created a promise in start_polling method that gets resolved when the item_promise_finish() is executed in then method of items_promise.
Once this promise in start_polling is resolved then i call handle_location method.
It works fine but sometimes i get error cannot read property then of undefined.
How can i fix it.
below is the code,
componentDidUpdate(prevProps, prevState) {
const {state, props} = this;
const current_id = props.item && props.item.id;
const prev_id = prevProps.item && prevProps.item.id;
if (current_id !== prev_id) {
this.stop_polling();
this.setState(this.get_initial_state(), () => {
this.start_polling();
});
} else {
const prev_poll = this.should_poll(prevProps, prevState);
const next_poll = this.should_poll(props, state);
if (prev_poll !== next_poll) {
if (next_poll) {
this.start_polling();
} else {
this.stop_polling();
}
}
if (this.props.location.search) {
this.start_polling().then(() => {
this.handle_location();
})
}
start_polling = () => {
if (this.should_poll(this.props, this.state)) {
this.poll();
return new Promise((resolve) => {
this.item_promise_finish=resolve;
});
}
};
poll = () => {
let still_polling = true;
if (this.cancel_poll_request) {
this.cancel_poll_request();
}
});
const items_promise = client.get_items(this.props.item.id,
cancel_poll_promise);
items_promise.then((request) => {
const next_items = [];
let something_changed = false;
for (const new_item of request.response) {
const old_item = this.state.items.find(
old_item =>
old_item.id === new_item.id);
if (old_item) {
next_items.push(old_item);
} else {
something_changed = true;
next_items.push(new_item);
}
}
if (something_changed) {
const next_state = {items: next_items};
this.setState(next_state);
}
}).then(() => {
if (still_polling) {
this.poll_timeout = setTimeout(this.poll, 100s);
}
this.item_promise_finish();
}).catch(this.props.notifications.request_error);
};
Could someone let me know where i am going wrong or what to be done to fix this. thanks.