Firebase event "<user> is writing..." like WhatsApp - firebase

Is there any manner to clone the whatsapp event "[user] is writing..." in Firebase events?
I have reading about the Firebase events in https://www.firebase.com/docs/web/api/ but I've not found anything about the issue.
Thanks.

I wrote such a typing indicator a while ago.
var ref = new Firebase('https://<your-app>.firebaseio.com');
var input = document.getElementById('input');
var typers = document.getElementById('typers');
var uid = Date.now(); // generate a fake user id
var timer;
// attach a listener that display all people current typing in a list
ref.on('value', function(snapshot) {
typers.innerText = '';
snapshot.forEach(function(typer) {
var li = document.createElement('li');
li.innerText = typer.key();
typers.appendChild(li);
});
});
// whenever the content of the textarea changes
input.addEventListener('input',function(e) {
// mark this user a "typing"
ref.child(uid).set(true);
// if we're counting down, stop the timer
if (timer) clearTimeout(timer);
// remove this user in 2 seconds
timer = setTimeout(function() {
ref.child(uid).remove();
}, 2000);
});
To see it in action, have a look at this JSBin.
The tweet where I announced it.

You can set a flag in the chat information
ex:
{ "chat1 :
{
"name: "Jon",
"isWriting" : true
}
"}
When sending a message to change the boolean value to "false" set a time to change the boolean value to false if no more connection to the Internet.

Related

Flutter : how to get newly added record from firebase real time database?

I'm using below code to retrieve all the data from my firebase chat room
void readDataFromFireBase() {
var databaseReference =
FirebaseDatabase.instance.reference().child("messages");
databaseReference
.child(chatroom.chatId)
.once()
.then((DataSnapshot snapshot) {
Map<dynamic, dynamic> values = snapshot.value;
values.forEach((key, value) {
setState(() {
chatMessageList.add(ChatMessage(
value["message"], value["fromUser"], value["timestamp"]));
chatMessageList.sort((a, b) {
var formatter = new DateFormat('MM/dd/yyyy, kk:mm');
var dateOne = formatter.parse(a.timestamp);
var selectedDate = formatter.parse(b.timestamp);
return dateOne.compareTo(selectedDate);
});
});
});
}
now how can i get notify my chat room when the new message has arrived
currently i'm using below code to listen child added event
listenDataFromFireBase() {
var db = FirebaseDatabase.instance.reference().child("messages");
db.child(chatroom.chatId).onChildAdded.listen((data) {
print("GET_NEW_DATA");
print(data.snapshot.value["message"] ?? '');
print(data.snapshot.value["fromUser"] ?? false);
print(data.snapshot.value["timestamp"] ?? '');
});
}
but there is one issue i'm facing this listenDataFromFireBase() load all the the data from particular room
My requirement is whenever new message added in chatroom i want to animate my message layout
How can i get notify my screen whenever new message will add in my chat room.
If need more information please do let me know. Thanks in advance. Your efforts will be appreciated.
As you've discovered onChildAdded fires immediately for any existing data, and after that also when any data is added. If you want to distinguish between these two cases, you'll need to combine an onChild listener and an onValue listener.
In the onValue listener, all you do is flag whether that event has happened:
databaseReference.onValue.listen((event) {
setState(() {
isInitialDataLoaded = true
});
});
Now do all your data processing in the onChildAdded listener, getting the message from the snapshot and adding it to the list. Then use the isInitialDataLoaded to detect whether this is initial data, or an update:
var db = FirebaseDatabase.instance.reference().child("messages");
db.child(chatroom.chatId).onChildAdded.listen((data) {
// TODO: get message from snapshot and add to list
if (isInitialDataLoaded) {
// TODO: alert the view about the new data
}
});
So you'll have two listeners on the same node. The Firebase SDK actually detects this situation and only reads the data from the server once, so there is no extra data being transferred in this case.
You can use onValue:
/// Fires when the data at this location is updated. `previousChildKey` is null.
Stream<Event> get onValue => _observe(_EventType.value);
But if you use onValue or onChildAdded, it will retrieve all the data under this chatroom.chatId, then when you data is added the onValue event will be fired again and will give you the new data.

FullCalendar with private google calendar event

I currently using google calendar on my website with the iframe you can insert. I tested Fullcalendar and I like what you can do with it.
But I would like to do same as the embed calendar, I would like to be able to create private event (not calendar, events). The sharing settings of the calendar is on public, but when using chrome, you can log with your google account and with the embed calendar you can see private event (if you have access to the calendar).
Is that possible with Fullcalendar ?
I figure out how to connect via OAUTH and get the private event when you are authentified.
By clicking on a button, you can connect to a google account (If already connected in browser, no button will appear and you will be log automaticly).
I follow this google example
<script type="text/javascript">
var clientId = '<your-client-id>';
var apiKey = '<your-api-key>';
var scopes = 'https://www.googleapis.com/auth/calendar';
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult && !authResult.error) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
GeneratePublicCalendar();
}
}
function handleAuthClick(event) {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
return false;
}
// Load the API and make an API call. Display the results on the screen.
function makeApiCall() {
// Step 4: Load the Google+ API
gapi.client.load('calendar', 'v3').then(function() {
// Step 5: Assemble the API request
var request = gapi.client.calendar.events.list({
'calendarId': '<your-calendar-id(The #gmail.com>'
});
// Step 6: Execute the API request
request.then(function(resp) {
var eventsList = [];
var successArgs;
var successRes;
if (resp.result.error) {
reportError('Google Calendar API: ' + data.error.message, data.error.errors);
}
else if (resp.result.items) {
$.each(resp.result.items, function(i, entry) {
var url = entry.htmlLink;
// make the URLs for each event show times in the correct timezone
//if (timezoneArg) {
// url = injectQsComponent(url, 'ctz=' + timezoneArg);
//}
eventsList.push({
id: entry.id,
title: entry.summary,
start: entry.start.dateTime || entry.start.date, // try timed. will fall back to all-day
end: entry.end.dateTime || entry.end.date, // same
url: url,
location: entry.location,
description: entry.description
});
});
// call the success handler(s) and allow it to return a new events array
successArgs = [ eventsList ].concat(Array.prototype.slice.call(arguments, 1)); // forward other jq args
successRes = $.fullCalendar.applyAll(true, this, successArgs);
if ($.isArray(successRes)) {
return successRes;
}
}
if(eventsList.length > 0)
{
// Here create your calendar but the events options is :
//fullcalendar.events: eventsList (Still looking for a methode that remove current event and fill with those news event without recreating the calendar.
}
return eventsList;
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
});
}
function GeneratePublicCalendar(){
// You need a normal fullcalendar with googleApi when user isn't logged
$('#calendar').fullCalendar({
googleCalendarApiKey: '<your-key>',
...
});
}
</script>
<script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>
And in your google api console, make sure in API & Auth -> ID
OAuth Javascript origin is set properly (Like http://localhost
https://localhost if you are working on a local website)
Leave Redirection and API referent empty.
Fullcalendar is a front-end solution only. Logging into a google account and any other authentication isn't part of it.
That said, it can be connected to a google calendar, but only if it's a public google calendar. If you want to interface it to a private google calendar, you would have to build in that functionality.
If you can get the gcal events with JS and handle authentication, getting them into FullCalendar is easy. But that first part takes a few steps. Take a look at the google calendar api docs for instruction.

Firebase on(child_added) some field 'undefined'

I am working on a real time application and i am using firebase with pure html and javascript (not angularJS).
I am having a problem where i saved user's data to firebase with the given code by firebase :
var isNewUser = true;
ref.onAuth(function(authData) {
if (authData && isNewUser) {
authData['status'] = 'active';
authData['role'] = 'member';
ref.child("users").child(authData.uid).set(authData);
}
});
This will add the authData to the /users/ node. As you can see that i also appended some custom fields to the authData, status and role.
Now i am using this code to get the user's data from firebase and display them.
ref4.on("value", function(snapshot) {
var snapshotData = snapshot.val();
console.log('username: '+snapshotData.status);
});
If i use on('value'), the status get printed out on the console but if i do it this way,
ref4.on("child_added", function(snapshot) {
var snapshotData = snapshot.val();
console.log('status: '+snapshotData.status);
});
It is showing undefined for the status. May i know what's wrong and how to fix this problem. Thank you.
Since value is returning the path provided by ref4, and child_added is returning each child of that path, it's unlikely both are going to have a key status.
Consider this data structure:
{
"users": {
"brucelee": {
"status": "awesome"
},
"chucknorris": {
"status": "awesomerest"
}
}
}
If I now query for this according to your incomplete example:
var ref = new Firebase('https://<instance>firebaseio.com/users/brucelee');
ref.on('value', function(snap) {
// requests the brucelee record
console.log(snap.name(), ':', snap.val().status); // "brucelee: awesome"
});
ref.on('child_added', function(snap) {
// iterates children of the brucelee path (i.e. status)
console.log(snap.name(), ':', snap.val().status); // THROWS AN ERROR, because status is a string
});
So to do this on child_added with a data structure like this (and presumably somewhat like yours), it would look as follows:
ref.on('child_added', function(snap) {
// iterates children of the brucelee path (i.e. status)
console.log(snap.name(), ':', snap.val()); // "status: awesome"
});

Am I using ForEach correctly?

I'm working on a presence-like system in firebase with following layout:
firebase {
user1 {
isOnline: true
}
user 2 {
isOnline: true
}
user3 {
isOnline: false
}
}
The isOnline booleans are what I am going to use later to output the names of the users that are online to the console
So for example, in the case above it would say:
user1 is online.
user2 is online.
Here is my code:
var gameRef = new Firebase("https://xxx.firebaseio.com/");
var userOnline = new Firebase('https://xxx/.info/connected');
userOnline.on('value', function (snapshot) {
if (snapshot.val()) {
gameRef.child(user).update({
isOnline : true
});
}
else {
gameRef.child(user).update({
isOnline : false
});
}
});
// for each user that is online, output to the console
gameRef.forEach(function (snapshot) {
var obj = snapshot.val();
if(obj.isOnline == true) {
console.log(obj.name + " is online.");
}
});
There seems to be a problem with my forEach, how can I fix this?
Thanks.
You cannot forEach over a ref, but only over a snapshot.
// for each user that is online, output to the console
gameRef.on('value', function(function(gamesSnapshot) {
gamesSnapshot.forEach(function (snapshot) {
var obj = snapshot.val();
if(obj.isOnline == true) {
console.log(obj.name + " is online.");
}
}
});
This code has two snapshot variables:
gameSnapshot is the data in the parent node
snapshot is the data of a specific player
Alternative
The approach above will download all players, even though you are only looking to deal with players that are online. It is more efficient in this case, to query Firebase so that it only returns players that are online.
// for each user that is online, output to the console
var onlinePlayers = gameRef.orderByChild('isOnline').equalTo(true);
onlinePlayers.on('child_added', function(function(snapshot) {
var obj = snapshot.val();
if(obj.isOnline == true) {
console.log(obj.name + " is online.");
}
});
The code now listens for the child_added event, since Firebase spoon-feeds us the players one at a time. You will probably also have to handle child_changed and child_removed, once you map the players to HTML elements.
Even though this will result in a bit more code, I would normally recommend using querying and the child_* events, since they limit the data that Firebase sends you both initially and when e.g. a player goes offline.

Firebase Displaying Other Users' username except yours Using Presence

Hi I'm new to firebase and was trying out the presence example on firebase everything is working normal. My issue is how do I display the username of others ONLY because everything I cant seem to find the solution for this because
I tried googling for an answer but none of the results are what I'm looking for.
I'm new to Firebase and non-mysql database so I dont know how to do a WHERE Statement on firebase
here is my code:
<body>
<div id="presenceDiv" class="l-demo-container example-base">
</div>
<script>
var name = "<?php echo $uname;?>";
var currentStatus = "★ online";
// Get a reference to the presence data in Firebase.
var userListRef = new Firebase("https://<URL>.firebaseio.com/");
// Generate a reference to a new location for my user with push.
var myUserRef = userListRef.push();
// Get a reference to my own presence status.
var connectedRef = new Firebase("https://<URL>.firebaseio.com//.info/connected");
connectedRef.on("value", function(isOnline) {
if (isOnline.val()) {
// If we lose our internet connection, we want ourselves removed from the list.
myUserRef.onDisconnect().remove();
// Set our initial online status.
setUserStatus("★ online");
}
else {
// We need to catch anytime we are marked as offline and then set the correct status. We
// could be marked as offline 1) on page load or 2) when we lose our internet connection
// temporarily.
setUserStatus(currentStatus);
}
});
// A helper function to let us set our own state.
function setUserStatus(status) {
// Set our status in the list of online users.
currentStatus = status;
myUserRef.set({ name: name, status: status });
}
function getMessageId(snapshot) {
return snapshot.name().replace(/[^a-z0-9\-\_]/gi,'');
}
// Update our GUI to show someone"s online status.
userListRef.on("child_added", function(snapshot) {
var user = snapshot.val();
$("<div/>")
.attr("id", getMessageId(snapshot))
.text(user.name + " is currently " + user.status)
.appendTo("#presenceDiv");
});
// Update our GUI to remove the status of a user who has left.
userListRef.on("child_removed", function(snapshot) {
$("#presenceDiv").children("#" + getMessageId(snapshot))
.remove();
});
// Update our GUI to change a user"s status.
userListRef.on("child_changed", function(snapshot) {
var user = snapshot.val();
$("#presenceDiv").children("#" + getMessageId(snapshot))
.text(user.name + " is currently " + user.status);
});
// Use idle/away/back events created by idle.js to update our status information.
document.onIdle = function () {
setUserStatus("☆ idle");
}
document.onAway = function () {
setUserStatus("☄ away");
}
document.onBack = function (isIdle, isAway) {
setUserStatus("★ online");
}
setIdleTimeout(5000);
setAwayTimeout(10000);
</script>
</body>
</html>
This script keeps on loading my 1st dummy username along the other dummy users that i tried logging on with. The same goes for the other dummy accounts the browser loads their username along with the others.. Whats causing this and how do I solve it? Please help
I'd simply identify and exclude the current user in you on(child_ handlers.
So for example:
// Update our GUI to show someone"s online status.
userListRef.on("child_added", function(snapshot) {
var user = snapshot.val();
if (user.name != name) {
$("<div/>")
.attr("id", getMessageId(snapshot))
.text(user.name + " is currently " + user.status)
.appendTo("#presenceDiv");
}
});

Resources