firebase update add new entry every time when fetching data using once - firebase-realtime-database

I wants to update the my child node data using below code snippet
let codeBankRef = firebase.database().ref().child("code")
codeBankRef.once('value', s => {
console.log(s.val())
if (s.exists()) {
console.log('snap exists', s.val())
this.setState({
loading: false,
codes: Object.keys(s.val()).map(k => ({ ...s.val()[k], firebaseUrl: k }))
})
return
}
else {
this.setState({
loading: false
})
}
})
When updating a child of node and fetching using once there is a new entry in the list. snapshot.ref.update({}) updates the child node but fetch an extra entry when using once function to fetch the value

Related

Trouble Deleting in React Native Firebase Firestore

I am trying to delete an object within a firebase firestore database. This was built in react native expo. When I run the code shown below, the console displays "Doc deleted", however, The object I meant to delete still shows in firebase as well as within my applicaton. Any advice would be greatly appreciated.
async function deleteProperty() {
await firebase.firestore().collection("Properties").get().then((documentSnapshot => {
documentSnapshot.forEach((doc) => {
if (doc.data().address == route.params.address) {
firebase.firestore().collection("Properties").doc().delete().then(() => {
console.log("Doc deleted")
}).catch((error) => {
console.error("Error removing document: ", error)
})
}
})
}))
}
It looks like you have to pass document id to doc() specifically.
firebase.firestore().collection("Properties").doc(doc.id).delete().then(() => {
console.log("Doc deleted")
}).catch((error) => {
console.error("Error removing document: ", error)
})
ref: https://firebase.google.com/docs/firestore/manage-data/delete-data#web-version-8

axios-on-rails, how to request set of records

I'm creating an app in Rails with a ReactJS front-end. In my front-end I'm using the axios-on-rails yarn package to make all my requests to my Rails api back-end.
Heres what I'm trying to do: for the main page of the site I want to implement an infinite scroll feature. For that to work well I need to be able to request small sets of records as the page continues to scroll. The only way I know how to pass records to my front-end is using:
axios.get('/posts.json')
.then((response) => {
...
})
.catch(error => console.log(error));
This returns ALL posts though, which eventually will be thousands. I don't want that happening. So how do I modify this request so that I only get the first 20 records or so?
Answer Details
Okay so I took a second look at pagination as #Gagan Gupta suggested and after a few hours got it to work. Heres what I did.
yarn add react-infinite-scroll to get the component needed.
For my feed component I did...
import React from 'react';
import Post from './Post';
import { connect } from 'react-redux';
import { loadPosts } from '../actions/posts';
import InfiniteScroll from 'react-infinite-scroller';
import axios from 'axios-on-rails';
const node = document.getElementById('owc_feed_payload');
const numberOfPosts = JSON.parse(node.getAttribute('number_of_posts'));
class Feed extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: props.posts,
hasMoreItems: true,
page: 1
};
}
componentDidUpdate(prevProps) {
if (this.props !== prevProps) {
this.setState({ posts: this.props.posts, hasMoreItems: this.props.hasMoreItems });
}
}
loadMore = (page) => {
axios.get('/posts.json', {
params: { page: page }
})
.then((response) => {
console.log(response.data);
this.props.dispatch(loadPosts(response.data));
this.setState({ hasMoreItems: this.state.posts.length < numberOfPosts ? false : true, page: this.state.page + 1 });
})
.catch(error => console.log(error));
}
render() {
let items = [];
this.state.posts.map((post, index) => {
items.push(
< ... key={index}>
...
</...>
);
});
return (
<InfiniteScroll
pageStart={0}
loadMore={this.loadMore}
hasMore={this.state.hasMoreItems}
loader={<p>Loading...</p>}>
{ items }
</InfiniteScroll>
);
}
}
const mapStateToProps = (state) => {
return {
timestamp: state.timestampReducer,
posts: state.postsReducer
}
};
export default connect(mapStateToProps)(Feed);
I used redux to manage the state of my posts. Next I added gem 'kaminari' to my gem file and ran bundle installed then added this line to my controller's index action: #posts = Post.all.order(created_at: :desc).page params[:page] and this to my model: paginates_per 5.
Now it scrolls and loads as expected! Awesome.
The solution would be to use pagination.
Every request will be bring only a set of records you'll specify in the method.
you can perform using gems like will_paginate, kaminari & this is the new gem called as pagy and they claim that it's faster than the other two.
Just increment the page parameter in the url after every request till the last page and you'll get the output you need.
I'm glad my opinion helped you :)
Change your JS code to this:
axios.post('/posts.json', {
params: {
page: page
}
}).then((response) => {
console.log(response.data);
...
}).catch(error => console.log(error));
}
Take a look at console.log(response) after axios then method so you can see the array of objects returning from the server. After then you can set it with .length property of method like:
axios.get('/posts.json')
.then((response) => {
if(response.data.length > 20){
console.log(response.data.slice(0,20))
}
})
.catch(error => console.log(error));

React Native NetInfo always returns offline

I'm currently trying to implement some functionality in my react native app where I use information stored locally if the device is offline, and perform a fetch if the device is online.
I used NetInfo after reading this How to handle network failure in React-Native, when network is off, but unfortunately I ran into an error where NetInfo always returns offline. I found this github issue, which recommended that I change the host in RCTReachability.m from 'htpp://apple.com' to 'apple.com'. However, I couldn't find a file with that name in the project directory. Instead I found the only mention of 'apple.com' in any file, which was in RCTNetInfo.m, which was in the correct form.
Does anybody know a way to fix this problem? Or possibly a different way to go about performing one action if the device is online, and another if the device is offline?
Here's the relevant code:
fetchData() {
NetInfo.isConnected.fetch().done((isConnected) => {
console.log('First, is ' + (isConnected ? 'online' : 'offline'));
if ( isConnected )
{
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
store.save('contacts', responseData.feed.entry)
.then(() => store.get('contacts'))
.then((contacts) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(contacts),
isLoading: false
});
})
})
.catch((error) => { console.error(error); });
}
else
{
store.get('contacts')
.then(contacts => {
if (contacts == null)
{
this.setState({
dataSource: this.state.dataSource.cloneWithRows(CONTACT_DATA),
isLoading: false
});
}
else
{
this.setState({
dataSource: this.state.dataSource.cloneWithRows(contacts),
isLoading: false
});
}
})
}
});
}

How to restore grid state during initialization?

I have Angular UI Grid where a user can change sorting order by clicking on column headers. I want to preserve user’s choice when the user leaves the controller and restore chosen sorting order when the user returns to the controller. UI Grid has saveState module so I am using it to save the state when the uses leaves the controller.
The issue is that I can’t restore this saved state. When should I call saveState.restore()? If I call it in onRegisterApi then it doesn’t work since columns aren’t constructed yet.
You can try this way
$scope.gridOptions = {
exporterMenuCsv: false,
enableGridMenu: true,
enableColumnResizing: true,
enableFiltering: true,
saveVisible: true,
saveOrder: true,
onRegisterApi: function (gridApi) {
$scope.gridApi = gridApi;
$timeout(function () {
$scope.restoreState(); //call my restore function
}, 100);
},
data: $scope.bookings
};
I call it just after I have filled the grid with data.
$scope.loadData = function () {
$q.all([
myDataLoaderFunction.$promise
])
.then(function (data) {
$scope.gridOptions.data = data[0];
var savedState = SomeServiceThatIStoredMyStateInto.getSavedGridState();
if (savedState) {
$scope.gridApi.saveState.restore($scope, savedState);
}
}, function () {
$scope.gridOptions.data = [];
});
};

Should I query the database as user types or left the job to Bloodhund?

I'm using Typeahead.js to search products in our webapp.
We are currently using Bloodhound to do a remote fetch of suggestions.
In the server, I'm doing a database query using the string entered by the user.
But I suspect, that the idea of using Bloodhound is not to do that in the server...
My JS code is as follow:
var products = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
limit: 205,
prefetch: 'Product/GetData?q=&ft=true',
remote: 'Product/GetData?q=%QUERY'
});
products.initialize();
$('#the-basics .typeahead').typeahead(null, {
name: 'products',
displayKey: 'name',
source: products.ttAdapter(),
minLength: 3,
templates: {
empty: [
'<div class="empty-message">',
'No products for current query',
'</div>'
].join('\n'),
suggestion: Handlebars.compile('<p><strong>{{name}}</strong></p>')
}
});
I have a Action in my Product controller to retrieve a list of products... so that on Prefetch I'm only returning the ACTIVE products... but then is you write something in the text box the remote option is triggered and returns all that matches the query.
My GetData action code:
public virtual JsonResult GetData(string q, bool ft = false)
{
if (ft == true)
{
var fetchTag = db.Products.AsNoTracking()
.Where(x => x.Active == true && x.idTenant == CurrentTenantID)
.OrderByDescending(x => x.Active).ThenBy(x => x.Nombre)
.Take(20)
.Select(x => new TagSys() { tag = x.idCaballo, name = x.Nombre }).ToList();
return Json(fetchTag, JsonRequestBehavior.AllowGet);
}
else
{
var fetchTag = db.Products.AsNoTracking()
.Where(x => x.idTenant == CurrentTenantID && x.Nombre.StartsWith(q.ToLower()))
.OrderByDescending(x => x.Active).ThenBy(x => x.Nombre)
.Take(20)
.Select(x => new TagSys() { tag = x.idCaballo, name = x.Nombre }).ToList();
return Json(fetchTag, JsonRequestBehavior.AllowGet);
}
}
First issue:[Solved] despite the fact that the query entered matched values in the Prefetch data, it returns values from the remote data. Why is this? ANSWER: The bloodhound tokenizer need a datum field/property as parameter. "value" was not a property in my datum... changing to "name" in my caso solved the issue.
Second: Should I query the database using the query value entered by user in the remote method, or should I return a big list and let Bloodhound do the work?
Third:[solved] I used the minLength: 3 option, hoping that it will start suggesting/searching just after 3 chars in the input, but I'm seeing that it is triggered after the first key pressed. ANSWER: this option is top level, not dataset related, so in my code, I replaced the null parameter in typeahead init with { minLength: 3} and it worked.

Resources