My database looks like that:
I know how to fetch genUserID and genUserID2 and renrder info to Flatlist. But how can i make two request to one fatlist?
I would like to get ids from eventAttenders/2188058178082419 and then get names from users database. User id comes from previous request.
My code:
constructor(props) {
super(props);
this.state = {
arrData:[]
};
}
componentDidMount = () => {
var ref = firebase.database().ref("eventAttenders/2188058178082419");
ref.once('value').then(snapshot => {
var items = [];
snapshot.forEach((child) => {
items.push({
id: child.val().id,
name: child.val().name,
email: child.val().yks,
});
});
this.setState({ arrData: items});
});
}
Umm, if understood your question correctly, the easy fix would be get all the ids first then with loop, get one more ref to the userlist and get the data.
constructor(props) {
super(props);
this.state = {
arrData:[]
};
}
componentDidMount = () => {
var ref = firebase.database().ref("eventAttenders/2188058178082419");
var items = [];
ref.once('value').then(snapshot => {
snapshot.forEach((child) => {
const { id } = child;
console.log(id) //make sure you are getting two ids genUserID and
// genUserID2 from 2188058178082419 ref
firebase.database().ref(`users/${id}`).once('value').then(childsnapshot => {
childsnapshot.forEach(keys => {
console.log(keys);
items.push({
name: keys.name,
phone: keys.phone,
});
});
});
this.setState({ arrData: items});
});
}
Related
I have a parent (organisation) document in firestore and multiple child documents. I want load he data based on if the parent or child was clicked in the same component.
The below code works, the data is shown, but updates to the child organisations are not shown in real time (I have to reload to see it.). I'm guessing it is because I'm binding the array orgArray and not the object org that I actually use to display the data. Is there a way to just bind the object and not the whole array?
<template>
<div class="route-container">
<div class="item__container">
<FmisTitle/>
<Hero
:orgName="org.name"
:orgLogo="org.logo"
:orgState="org.state"
:orgNumber="org.number"
:orgType="org.type"
:orgDateStart="org.dateStart"
:orgDateEnd="org.dateEnd"
:orgDateStartF="org.dateStartFunctional"
:orgDateEndF="org.dateEndFunctional"
:orgCoverImage="org.coverImagex745"
:childRef="org.id"
:orgRef="orgRef"
/>
<Contact
:orgEmail="org.email"
:orgPhone="org.phoneNumber"
:orgAddress="org.address"
:orgWebsite="org.website"
:orgSocials="org.socials"
:childRef="org.id"
:orgRef="orgRef"
/>
<ButtonDuo/>
</div>
</div>
</template>
export default {
data() {
return {
org: {},
orgArray: [],
orgRef: '',
};
},
created() {
firebase.auth().onAuthStateChanged((user) => {
firestore.collectionGroup('people').where('userId', '==', user.uid).get().then((query) => {
query.forEach((userRef) => {
const orgRef = userRef.ref.parent.parent.id;
this.orgRef = orgRef;
if (!this.$route.params.parent) {
const organisation = firestore.collection('organisations').doc(orgRef).collection('childOrganisations').where('name', '==', this.$route.params.id);
this.$bind('orgArray', organisation).then((doc) => {
const org = doc[0];
this.org = org;
});
} else {
const organisation = firestore.collection('organisations').doc(orgRef);
this.$bind('org', organisation);
}
});
});
}, (error) => {
console.log(error);
});
},
}
I solved this by using the id from the childOrg and getting the data with that id, that way I could bind the data object directly.
firebase.auth().onAuthStateChanged((user) => {
firestore.collectionGroup('people').where('userId', '==', user.uid).get().then((query) => {
query.forEach((userRef) => {
const orgRef = userRef.ref.parent.parent.id;
this.orgRef = orgRef;
if (this.$route.query.parent !== 'true') {
firestore.collection('organisations').doc(orgRef).collection('childOrganisations').where('name', '==', this.$route.params.id)
.get()
.then((q) => {
q.forEach((ref) => {
const orgId = ref.id;
const organisation = firestore.collection('organisations').doc(orgRef).collection('childOrganisations').doc(orgId);
this.$bind('org', organisation);
});
});
} else {
const organisation = firestore.collection('organisations').doc(orgRef);
this.$bind('org', organisation);
}
});
});
}, (error) => {
console.log(error);
});
Fetching data from firebase database and my output to simulator is duplicated. I know why data is pushed 2 times to 'items'. How can i solve this issue and push items from every child to 'addData' only once?
My code:
constructor(props) {
super(props);
this.state = {
arrData:[]
};
}
componentDidMount = () => {
var self = this;
var items = [];
database.ref("eventAttenders/2188058178082419").orderByKey().once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
const key = childSnapshot.key;
database.ref(`users/${key}`).once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var data = snapshot.val();
items.push({
name: data.name,
phone: data.phone,
});
});
});
});
});
self.setState({arrData: items})
}
Database screenshot:
Simulator screenshot:
Because you are adding the push method in snapshot.forEach(function(childSnapshot) { this not required, try removing it.
componentDidMount = () => {
var self = this;
var items = [];
database.ref("eventAttenders/2188058178082419").orderByKey().once("value")
.then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
var key = childSnapshot.key;
const key = childSnapshot.key;
database.ref(`users/${key}`).once("value")
.then(function(snapshot) {
var data = snapshot.val();
items.push({
name: data.name,
phone: data.phone,
});
});
});
});
self.setState({arrData: items})
}
I have the following controller action
[HttpPost]
[Route("api/Tenant/SetTenantActive")]
public async Task<IHttpActionResult> SetTenantActive(string tenantid)
{
var tenantStore = CosmosStoreFactory.CreateForEntity<Tenant>();
var allTenants = await tenantStore.Query().Where(x => x.TenantDomainUrl != null).ToListAsync();
foreach(Tenant ten in allTenants)
{
ten.Active = false;
await tenantStore.UpdateAsync(ten);
}
var tenant = await tenantStore.Query().FirstOrDefaultAsync(x => x.Id == tenantid);
if (tenant == null)
{
return NotFound();
}
tenant.Active = true;
var result = await tenantStore.UpdateAsync(tenant);
return Ok(result);
}
And my react code:
import React, { Component } from 'react';
import { Table, Radio} from 'antd';
import { adalApiFetch } from '../../adalConfig';
import Notification from '../../components/notification';
class ListTenants extends Component {
constructor(props) {
super(props);
this.state = {
data: []
};
}
fetchData = () => {
adalApiFetch(fetch, "/Tenant", {})
.then(response => response.json())
.then(responseJson => {
if (!this.isCancelled) {
const results= responseJson.map(row => ({
key: row.ClientId,
ClientId: row.ClientId,
ClientSecret: row.ClientSecret,
Id: row.Id,
SiteCollectionTestUrl: row.SiteCollectionTestUrl,
TenantDomainUrl: row.TenantDomainUrl
}))
this.setState({ data: results });
}
})
.catch(error => {
console.error(error);
});
};
componentDidMount(){
this.fetchData();
}
render() {
const columns = [
{
title: 'Client Id',
dataIndex: 'ClientId',
key: 'ClientId'
},
{
title: 'Site Collection TestUrl',
dataIndex: 'SiteCollectionTestUrl',
key: 'SiteCollectionTestUrl',
},
{
title: 'Tenant DomainUrl',
dataIndex: 'TenantDomainUrl',
key: 'TenantDomainUrl',
}
];
// rowSelection object indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
if(selectedRows[0].key != undefined){
console.log(selectedRows[0].key);
const options = {
method: 'post',
body: {tenantid:selectedRows[0].key},
};
adalApiFetch(fetch, "/Tenant/SetTenantActive", options)
.then(response =>{
if(response.status === 200){
Notification(
'success',
'Tenant created',
''
);
}else{
throw "error";
}
})
.catch(error => {
Notification(
'error',
'Tenant not created',
error
);
console.error(error);
});
}
},
getCheckboxProps: record => ({
type: Radio
}),
};
return (
<Table rowSelection={rowSelection} columns={columns} dataSource={this.state.data} />
);
}
}
export default ListTenants;
focus only on the onchange event,
And the screenshot:
And it looks like the request gets to the webapi (I attached the debugger)
Update:
Basically If I dont put FromBody I need to send the parameter via querystring.
However if I put from Body and I send the parameter in the body, its received null on the webapi
Add [FromBody] before your input parameter in your action method like this:
public async Task<IHttpActionResult> SetTenantActive([FromBody] string tenantid)
Then, convert your selected row key into string
const options = {
method: 'post',
body: { tenantid : selectedRows[0].key.toString() }
};
I have a Component that is a TypeAhead. When the user enters the component page Apollo pulls an initial query of 5 players that is used for the typeahead. Ideally i would like to skip this initial query but thats another thing entirely. So the query is filled with 5 players. Player1 to Player5, When i start typing in the typeahead searching for Player10, I select Player10 and it dispatches an action to make it the currently selected Player. However after I trigger an onBlur or leave the box, Apollo dispatches a Redux action of APOLLO_QUERY_RESULT_CLIENT which sets all the typeAhead back to Player1 to Player5 my initial query instead of having it set correctly to Player10. How do you prevent that APOLLO_QUERY_RESULT_CLIENT from dispatching as it dispatches anytime i dispatch an action that i created myself.
class TypeAhead extends Component {
constructor() {
super();
this.state = {
value: ''
};
}
renderInputComponent = (inputProps) => {
let {selectedSuggestion} = this.props;
return (
<div className="inputContainer">
<img className="type-ahead__image" alt="" src={getImageURL(selectedSuggestion.id)} />
<TextField floatingLabelText="Search Player" {...inputProps} />
</div>
)
}
onChange = (event, { newValue }) => {
this.setState({
value: newValue
});
};
shouldRenderSuggestions(value) {
return value.trim().length > MIN_SEARCH_LENGTH;
}
onSuggestionsFetchRequested = ({ value }) => {
// debugger;
if(/^[a-z .,-]+$/i.test(value)) {
this.props.data.refetch({name: value});
}
};
onSuggestionsClearRequested = () => {
// debugger;
// this.setState({
// suggestions: []
// });
// this.props.data.Players = [];
};
onBlur = () => {
if (this.state.value.toLowerCase() === this.props.data.Players[0].name.toLowerCase()) {
let suggestion = this.props.data.Players[0];
this.props.onSuggestionSelected(null, { suggestion });
}
}
render() {
console.log(this.props.data.Players)
let suggestions = this.props.data.Players || [];
let { onSuggestionSelected } = this.props;
let { value } = this.state;
let inputProps = {
value,
onChange: this.onChange,
onBlur: this.onBlur
};
return (
<div>
<Autosuggest
suggestions={suggestions}
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
getSuggestionValue={getSuggestionValue}
renderSuggestion={renderSuggestion}
shouldRenderSuggestions={this.shouldRenderSuggestions}
onSuggestionSelected={onSuggestionSelected}
renderInputComponent={this.renderInputComponent}
inputProps={inputProps}
/>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
selectedSuggestion: state.selectedSuggestion
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSuggestionSelected(event, {suggestion}) {
dispatch(actions.selectSuggestion(suggestion));
// dispatching action causes apollo to requery and pull inital query causing issues.
},
onSuggestionUnselected() {
dispatch(actions.unselectSuggestion());
}
}
}
const TypeAheadWithData = graphql(TypeAheadQuery, {
options: ({ name }) => ({ variables: { name } })
})(TypeAhead);
const TypeAheadWithDataAndState = connect(mapStateToProps, mapDispatchToProps)(TypeAheadWithData);
export default TypeAheadWithDataAndState;
const TypeAheadWithData = graphql(TypeAheadQuery, {
options: ({ name }) => ({ variables: { name } })
})(TypeAhead);
Whenever the name prop changes, the query will be run again. It is very likely that you reset the name just before the query is run again.
If this is not the case, you can know why the graphql container is refetching by debugging the networkStatus. You also need to add options: { notifyOnNetworkStatusChange: true }
I try to create a spinner when loading data from Firebase. I am new to this, so sorry for the basics question. I've come up with this code so far. Declare state , and try to add a conditional statement, but no success:
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
items: [],
loading: true
};
this.itemsRef = this.getRef().child('items');
this._handleResults = this._handleResults.bind(this);
}
listenForItems(itemsRef) {
this.setState({
loading: true
});
itemsRef.on('value', (snap) => {
// get children as an array
var items = [];
snap.forEach((child) => {
items.push({
french: child.val().french,
english: child.val().english,
english_erudite: child.val().english_erudite,
_key: child.key
});
});
this.setState({
dataSource: this.state.dataSource.cloneWithRows(items),
items: items,
loading: false
});
});
}
_renderItem(item) {
const { navigate } = this.props.navigation;
const {loading}= this.state;
if (this.state.loading){
return <Spinner/>
}else{
return(<ListItem item={item} onPress={() =>
navigate('Details', {...item} )} />);
}
}
}