React native firebase database on value change not triggered - firebase

I have a react native app and using firebase database.
I try to use the on or once functions to get items from database but I don't know what I am doing wrong because I don't get any data.
This is my code to get data from firebase database:
firebase.database().ref("messages/").once('value', snapshot => {console.log("snapshot value", snapshot)});
I try the command from above also with on instead of once and same result. The console.log is never called.
When I am adding messages everything it's ok and the messages appear in the firebase console. For adding messages I am doing like this:
firebase.database().ref("messages/").push(message);
For firebase I am using this library: rnfirebase.io
This are the versions used:
React: 16.6.0-alpha.8af6728
React native: 0.57.4
React native firebase: 5.0.0

The Firebase once returns a promise so you have to use then after using value.
The code should be like
firebase.database().ref('tableNameHere').once('value').then(snapshot => {
if(snapshot.exists()){
console.log(snapshot.val());
}
}).catch(err => console.log(err));
when using on value the function will invoke on change in value like on CRUD operation
firebase.database().ref('tableNameHere').on('value', snapshot => {
if(snapshot.exists()){
console.log(snapshot.val());
}
},(err) => console.log(err))

Related

Redirect to a specific screen from React Native Firebase Push Notifications based on a Deeplink

I got a problem,
1 ) I'm using Firebase to send remote Push Notifications, i test by sending from FCM tester.
2 ) I've activated Deep-Linking in my project and started to use it.
3 ) In FCM tester i pass this key value into "notifications.data" :
{ "link" : "MY_LINK" }
Now i want my app to be able to recognize there is a deepLink in it & read it.
Which i achieved to do somehow but not the way i was looking for.
What i did :
NotificationContextProvider.ts
useEffect(() => {
const unsubscribeClosedApp = messaging().onNotificationOpenedApp(
remoteMessage => {
addNotification(remoteMessage);
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
redirectFromKey(remoteMessage.data?.redirection);
console.log(remoteMessage.data, 'remote message data');
console.log(remoteMessage, 'remote message full');
console.log(remoteMessage.notification?.body, 'remote message body');
console.log(remoteMessage.notification?.title, 'remote message title');
if (remoteMessage.data?.link === 'https://[MY-LINK]/TnRV') {
console.log(remoteMessage.data?.link, 'Deeplink detected & opened');
navigation.navigate({
name: 'Logged',
params: {
screen: 'Onboarded',
params: {
screen: 'LastAnalyse',
},
},
});
}
},
);
And it's working fine but it's not based on reading a link, but by comparing a value and it's not what i'm trying to achieve.
Firebase Doc' give us a way to do this : https://rnfirebase.io/dynamic-links/usage#listening-for-dynamic-links
This is what Firebase suggests :
import dynamicLinks from '#react-native-firebase/dynamic-links';
function App() {
const handleDynamicLink = link => {
// Handle dynamic link inside your own application
if (link.url === 'https://invertase.io/offer') {
// ...navigate to your offers screen
}
};
useEffect(() => {
const unsubscribe = dynamicLinks().onLink(handleDynamicLink);
// When the component is unmounted, remove the listener
return () => unsubscribe();
}, []);
return null;
}
And i have no clue how to make it works.
I got to mention that deep-links are correctly setup in my project and working fine, my code is in Typescript.
Basicaly you can find on this web page what i'm trying to achieve but i want to use Firebase/messaging + Dynamic links. My project don't use local notifications and will never do : https://medium.com/tribalscale/working-with-react-navigation-v5-firebase-cloud-messaging-and-firebase-dynamic-links-7d5c817d50aa
Any idea ?
I looked into this earlier, it seems that...
You can't send a deep link in an FCM message using the firebase Compose Notification UI.
You probably can send a deep link in an FCM message using the FCM REST API. More in this stackoverflow post.
The REST API looks so cumbersome to implement you're probably better off the way you're doing it: Using the firebase message composer with a little data payload, and your app parses the message data with Invertase messaging methods firebase.messaging().getInitialNotification() and firebase.messaging().onNotificationOpenedApp().
As for deep linking, which your users might create in-app when trying to share something, or you might create in the firebase Dynamic Links UI: For your app to notice actual deep links being tapped on the device, you can use Invertase dynamic links methods firebase.dynamicLinks().getInitialLink() and firebase.dynamicLinks().onLink().

Firebase emulator always returns Error: 2 UNKNOWN after trying out the firestore background trigger functions?

** This is that my firestore (emulator) looks like**
I am trying to practice learning about cloud functions with firebase emulator however, I am running into this probably more often than I expected. I hope it is my end's problem.
I am trying to write a function where when the user made the https request to create an order, the background trigger function will return out the total (quantity * price) to the user. The later part is still WIP at the moment; I am currently just trying to understand and learn more about cloud functions.
This is the https request code I have to add the item, price, and quantity to my firestore. It works well and as intended.
exports.addCurrentOrder = functions.https.onRequest(async (req, res) => {
const useruid = req.query.uid;
const itemName = req.query.itemName;
const itemPrice = req.query.itemPrice;
const itemQuantity = req.query.itemQuantity;
console.log('This is in useruid: ', useruid);
const data = { [useruid] : {
'Item Name': itemName,
'Item Price': itemPrice,
'Item Quantity': itemQuantity,
}};
const writeResult = await admin.firestore().collection('Current Orders').add(data);
res.json({result: data});
});
This is the part that's giving me all sorts of errors:
exports.getTotal = functions.firestore.document('Current Orders/{documentId}').onCreate((snap, context) => {
const data = snap.data();
for(const i in data){
console.log('This is in i: ', i);
}
return snap.ref.set({'testing': 'testing'}, {merge: true});
});
Whenever I have this, the console will always give me:
functions: Error: 2 UNKNOWN:
at Object.callErrorFromStatus (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/call.js:30:26)
at Object.onReceiveStatus (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/client.js:175:52)
at Object.onReceiveStatus (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:341:141)
at Object.onReceiveStatus (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/client-interceptors.js:304:181)
at Http2CallStream.outputStatus (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/call-stream.js:116:74)
at Http2CallStream.maybeOutputStatus (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/call-stream.js:155:22)
at Http2CallStream.endCall (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/call-stream.js:141:18)
at Http2CallStream.handleTrailers (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/call-stream.js:273:14)
at ClientHttp2Stream.<anonymous> (/Users/user/firecast/functions/node_modules/#grpc/grpc-js/build/src/call-stream.js:322:26)
at ClientHttp2Stream.emit (events.js:210:5)
Caused by: Error
at WriteBatch.commit (/Users/user/firecast/functions/node_modules/#google-cloud/firestore/build/src/write-batch.js:415:23)
at DocumentReference.create (/Users/user/firecast/functions/node_modules/#google-cloud/firestore/build/src/reference.js:283:14)
at CollectionReference.add (/Users/user/firecast/functions/node_modules/#google-cloud/firestore/build/src/reference.js:2011:28)
**at /Users/user/firecast/functions/index.js:43:76**
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:593:20
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:568:19
at Generator.next (<anonymous>)
at /usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:8:71
at new Promise (<anonymous>)
at __awaiter (/usr/local/lib/node_modules/firebase-tools/lib/emulator/functionsEmulatorRuntime.js:4:12)
⚠ Your function was killed because it raised an unhandled error.
Even if I comment out the function that I think is giving me the error, I will still run into this problem (and when I run the sample function found on the official cloud function guide too!)
I know there is definitely something that I am doing horribly wrong on the background trigger (and would love to have someone be kind enough to show me how to write such function/get me startted)
What am I doing wrong here? Or is this some sort of the emulator bug?
I think I found it. Although I think there is better solution possible.
On completely new system+firebase I have used this firebase emulators tutorial to create first onCreate trigger called makeUppercase and it worked. Than I added your getTotal and it was not working and as well it spoiled the makeUppercase trigger as well!
I started to test some changes. Tried many times and, finally, I have removed "space" character from collection name like this:
exports.getTotal = functions.firestore.document('CurrentOrders/{documentId}')...etc.
Both triggers started working as well (used fresh VM with Windows+node12). It's possible that it will be working on real Firestore instance. So it seems the "space" in collection name is generating some errors in whole index.js.

How to stub external services in Firebase emulator?

I have one firestore trigger function that is creating DNS record based on the slug attribute. I have some unit tests where I am stubbing #google-cloud/dns module so no external HTTP request is made. However, I have several integration tests as well. Those are hitting local firebase emulator (localhost:8080).
For instance, whilst testing firestore rules, I am simply calling db.collection('path').add(model) and that is triggering callable function inside emulator process.
Tests are running by this command: firebase emulators:exec 'mocha --config spec/.mocharc.yml
At first, it is initializing emulators and then running tests. As far as I understood these are different processes. So inside the mocha process, I am able to stub, mock with modules. On the other hand, inside the emulator process, functions, modules, dependencies are already loaded as it is. So when I am running this test script for testing firestore rules inside mocha test suite:
await assertSucceeds(db.doc('stores').set(store));
It actually runs the handler and sends the request to the google cloud DNS. Did anyone face issues something like this? Thanks in advance.
I'm facing the same situation. My plan is to make the Cloud Function initialize itself with a stubbed service that will record its own calls to a log collection in Firestore when NODE_ENV=test. Then the test will check whether the call was recorded by querying that collection.
test('fanOutCategoryFields', async () => {
// Initialize Firebase and seed test data
const app = await setup({
'categories/1': {
name: 'Some Name',
},
'posts/1': {
categoryId: '1',
},
})
// Update a document (will trigger the Cloud Function)
await app
.firestore()
.collection('categories')
.doc('1')
.update({ name: 'New Name' })
// Wait for the Cloud Function to run
await new Promise(resolve => setTimeout(resolve, 3000))
// Query the collection where function calls are recorded
const calls = await app
.firestore()
.collection('_calls')
.get()
.then(snap => snap.docs.map(snap => snap.data()))
// Check if Algolia was called with the expected arguments
expect(calls).toEqual([
{
fn: 'algolia.update',
args: ['products', '1', { categoryName: 'New Name' }],
},
])
})

Image upload with Firebase React Native

I want to upload an image to Firebase Storage from a React Native app, the Firebase web sdk only works on iOS so I am giving Firebase React Native a go. The docs are empty but someone pointed my to the old docs so my code looks like this.
firebase.storage().ref('/rn-firebase2.jpg').putFile(imgFile.uri)
.on('state_changed', snapshot => {
//Current upload state
console.log('state_changed: ', snapshot);
}, err => {
//Error unsubscribe();
console.log('err: ', err);
}, uploadedFile => {
//Success unsubscribe();
console.log('uploadedFile: ', uploadedFile);
});
When ran, I get
"Possible Unhandled Promise Rejection (id: 0):". A file is uploaded to
the Cloud Storage but it unusable.
Anyone has successfully gotten this to work on iOS and Android? Any help would be much appreciated, thanks!

How to get access to native Firebase object when using angularfire2?

I'm using AngularFire2 (2.0.0-beta.2) incombination with angular2 (2.0.0-rc.4). I'd like to get access to the native firebase object (not the AngularFire root object) from Angularfire2.
Within my component, I want to make calls like:
firebase.auth().currentUser.updateEmail("user#example.com")
where firebase is the native firebase object, like that you get from the fragment below:
<script src="https://www.gstatic.com/firebasejs/3.1.0/firebase.js"></script>
<script>
// Initialize Firebase
// TODO: Replace with your project's customized code snippet
var config = {
apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "https://databaseName.firebaseio.com",
storageBucket: "bucket.appspot.com",
};
firebase.initializeApp(config);
</script>
But I don't understand how to setup my angular2 component so that the firebase object is visible within it. Probably a very simple problem to solve, but I don't know how to solve -- I'm not an angular2 expert. I was hoping there would be and AngularFire api to get the object, but there is not.
Also, the reason that I'm trying to do this is that I don't think the angularfire2 api's are complete yet (thats understandable as its still in beta) and I'm trying to work around this. For example I want to update the users email address or password, or send them the forgotten password email. None of this functionality seems to exist yet in AngularFire2, so I'm trying to implement using the native Firebase object.
If you're reading this in September 2016 onwards, this approach might sound good to you.
See the code for superior understanding:
import { Component, Inject } from '#angular/core';
import { AngularFire, FirebaseApp } from 'angularfire2';
#Component({
templateUrl: 'app/auth/resetpassword.component.html'
})
export class ResetpassComponent {
public auth: any;
constructor(private af: AngularFire, #Inject(FirebaseApp) firebaseApp: any) {
this.auth = firebaseApp.auth()
console.log(this.auth);
}
// formData.value.email = 'your#email.com';
onSubmit(formData) {
if(formData.valid) {
console.log('Sending email verification');
this.auth.sendPasswordResetEmail(formData.value.email)
.then( (response) => {
console.log('Sent successfully');
})
.catch( (error) => {
console.log(error);
})
}
}
}
In English:
Import Inject and FirebaseApp
Make available in your component
Start using all the native javascript SDK functions and methods, such as sendPasswordResetEmail()
Doing a auth. doesn't autocomplete with the available methods and functions, so you might need the docs close to you, such as this: https://firebase.google.com/docs/auth/web/manage-users
Any thanks? Give to #cartant : https://stackoverflow.com/a/39069813/1757321
I'm going to try and answer my own question. Let me first say that I'm sure my answer is not the most elegant solution, I'm not yet a javascript/typescript/angular expert. But my answer does work -- even if I don't completely understand.
I used angular-cli to setup my project which is based on angular2 and the latest firebase. Apparently when you use this to setup your project there is a global object created with the name "firebase" in existence. One way to make it visible within your angular 2 component is to put this declaration at the global level in you component (right after the import statements and before your class declaration).
declare var firebase : any;
After you do this the global firebase object is available for use in your component.
RanchoSoftware's solution did not work for me, i used
import {AngularFireModule} from "angularfire2";
import *as firebase from 'firebase';
within the imports in the app.module.ts file
found here:
https://github.com/angular/angularfire2/issues/445

Resources