According to the Firebase documentation:
Value events are always triggered last and are guaranteed to contain updates from any other events which occurred before that snapshot was taken.
Here is a simple example (jsbin) where child_added fires before value. This behavior was confirmed using the currently latest Firebase version (2.3.1):
var ref = new Firebase("https://reform.firebaseio.com");
ref.child('pets').once('value', function(snapshot) {
snapshot.forEach(function(pet) {
console.log("Pet: " + pet.key());
pet.ref().child('food').once('value', function (foods) {
console.log('value event called for ' + pet.key());
});
pet.ref().child('food').once('child_added', function (foods) {
console.log('child_added event called for ' + pet.key());
});
});
});
In this example, the console log will be:
Pet: cat
Pet: dog
value event called for cat
child_added event called for cat
value event called for dog
child_added event called for dog
Why does the child_added event fire last in this case? Does this not violate the guarantee per the documentation?
To summarize the excellent feedback in the comments and by Firebase Support:
It makes most sense here to use on() instead of once() to register the event listener. In the example of the original post, and to quote Firebase Support:
The on() callback is registered, and when the once() callback is registered it is ordered in reference to the on() callback. Once the once() callback is fired, it's automatically deregistered. Even though the execution of the events are done in a certain order (due to javascript being single threaded), they are being calculated separately from each other.
Frank's correction to that example shows this in action.
The modified example again breaks the "guarantee" because (Firebase Support):
The data is already locally on the client. So once you have run ref.child('pets').on() and the callback happens, all the data under /pets has been retrieved to the client. Now in the callback processing, you are adding additional callbacks to the existing data. When the callback is being added, the client library is immediately firing the callback without waiting for the second one to be registered since all the data is available.
Since I would like to enforce the guarantee in this case where the data is local, I simply register the child_added listener before the value listener, as demonstrated in the correction to the modified example.
Related
I found next executing itself infinitely. I think this is an abstraction of my code that replicates the problem:
function next() {
game.set(newObj)
}
game.child(`user1`).orderByKey().on(`value`, next);
The solution was to insert a remove the event listener:
game.child(`user1`).orderByKey().off() //new
function next() {
game.set(newObj)
}
game.child(`user1`).orderByKey().on(`value`, next);
My initial understanding was ref.orderByKey().on('value', ...) executed its handler once. Is there anything you can see here that explains why the handler executed infinitely?
If not, perhaps another piece of code was responsible - like one of the child_changed event listeners I have. My child_changed listeners all listen for a change in various parts of game. Surely updating game to a new object would trigger them. However, none of their callbacks are next so I think they don't play a role in retriggering next.
My initial understanding was ref.orderByKey().on('value', ...) executed its handler once. Is there anything you can see here that explains why the handler executed infinitely?
No, that's exactly the way it's supposed to work. A listener attached using on() will be invoked every time the data is seen to change. It will continue to do so until the listener is removed. To do that, you must call off() after you call on().
If you want to execute a query just once, use once() instead of on().
As I understand, when this following line of code is interpreted/executed by Javascript
ref.on('value',callback)
(similar to document.addEventListener('click', callback)). The callback gets attached to the el/object for that event such that when that event executes then the attached callback (event handler) gets fired.
But I observe that firebase 'value' event will automatically fire when there is some data at this ref, when the above line of code is interpreted/executed by Javascript even though there is NO trigger such as add/delete/modify operation that happens to that ref.
Is this interpretation/assumption correct or the value event works just like any other event that trigger from add/delete/modify operations. In that case what would be that trigger?
Also, if the value event fires automatically does it actually do an async/network call to the firebase database on that ref and then fetches that data (snapshot) or is the ref data cached at the client side i.e. no async/network request.
Can anybuddy, clarify both this confusion? Your help is appreciated.
According to the documentation:
You can use the value event to read a static snapshot of the contents
at a given path, as they existed at the time of the event. This method
is triggered once when the listener is attached and again every time
the data, including children, changes. The event callback is passed a
snapshot containing all data at that location, including child data.
If there is no data, the snapshot will return false when you call
exists() and null when you call val() on it.
When you attach a listener, the SDK will use its persistent connection to the database to check if there is new data. If there is not any new data, then the locally cached data is provided.
I'm using fullcalendar (the v4 alpha) to arrange events.
I have an eventDragStop callback that I'm trying to use to set an extendedProp for an event, marking that the event has been altered.
eventDragStop: function (info) {
calendar.getEventById(info.event.id).setExtendedProp("extra2", true)
}
Using the code above, it doesn't work. If I alert(info.event.id), I can see that the correct ID is being called for the event that has been dragged, and get no errors.
If I have three events on the calendar, with IDs: 1, 2, 3, and use the following code:
eventDragStop: function (info) {
calendar.getEventById(1).setExtendedProp("extra2", true)
}
So, explicitly stating to change ID number 1, rather than the event in the callback.
If I drag event number 1, this doesn't work either. However, if I drag event 2 or 3, it will work and change event 1.
Vice versa, any event I explicitly state, it will be able to change that event, providing that was not also the event that triggered the eventDragStop callback.
Can anyone tell me why this is?
https://fullcalendar.io/docs/v4/eventDragStop says (of itself as a callback)
"It is triggered before the event’s information has been modified"
So I think what is happening here is that fullCalendar effectively overwrites any change you make to the event data during this callback.
I think this is because the event object maybe gets replaced with a new version (constructed based on its final resting place) some time after this callback runs.
I haven't verified this by looking at the source code but it's a logical explanation for the issue you're seeing, and it also makes some sense that the event object would get updated (with new dates/times etc) after dragging is complete, and that this might in fact involve a full refresh of the object data at that time.
Anyway, that's why when dragging event 1 you then fail to persist any updates to event 1's other data, but when dragging event 2 or 3 you are able to persist the changes to event 1 - because in that instance event 1's data is not being replaced at a later time as a result of the dragging being completed.
Instead of using eventDragStop, you should modify the event during eventDrop (https://fullcalendar.io/docs/v4/eventDrop) instead. This callback occurs after fullCalendar has completely finished processing the dragging/dropping and updated the event times etc. Therefore any further changes you make to the event data I would expect should be preserved.
I'm trying to get data with server-sent event, what the different using
source.onmessage vs source.addEventListener?
source.onmessage is the built in function wrapper for EventSource that is triggered when new data is sent to the client. It fires when no event attribute is returned (default) and doesn't fire when it is set.
addEventListener is similar, but differs in that it listens for a specific event name, and triggers on its presence, allowing you to separate your functionality for multiple events. You can then parse the JSON data returned. It can be used on any event type. Have a look at this example:
source.addEventListener("login", function(e) {
// do your login specific logic
var returnedData = JSON.parse(e);
console.log(returnedData);
}, false);
This snippet will listen for a server message with event specified as login, then it triggers the callback function.
More info:
https://developer.mozilla.org/en-US/docs/Server-sent_events/Using_server-sent_events
http://html5doctor.com/server-sent-events/
I assume you're talking about addEventListener('message') vs onmessage. They do the same thing, but I'd recommend using onmessage because with addEventListener, there's always a possibility of unexpectedly adding the same listener twice, e.g. due to a laggy page reload, or some hot-reload during development. In those cases the handler function could fire twice on every event, which leads to weird behaviors.
Scenario :- a json with checked & unchecked item count needs to be sent to a common function which in turn does some basic validation or shows error. There are different function each handle by different css/js team which call this function & depending on the common function result (true/false) each team/module that provided the json with check/uncheck status does the relevant action. Thus both common function (say getcount) & every independent team calling this function rely on the result of common function manipulate the dom/css independently & the common function too manipulate dom independently.
Instead of conventional way of calling function (say getCount({"chk" : 2 , "unchk" : 4})) i am looking for pusblish/subcribe method which is more cleaner as in Jquery & easy to convey to all as only topic name & contract/json needs to describe (also less if/else clause). Since common function is subscriber & when every independent function publishes the resultant chk/unchek json the common function can easily do the manipulation using the publish/subscribe approach but the independent method has to do counter action as well which is only possible if subscribe function can send the result. I know javascript is asynchronous also i understand that common method can publish (say "resultOfGetCount") which every independent function/module can listen to & do the action but is there any way in either in plain javascript or jquery where in on which subscriber can send the publisher the result in a way similar to $.ajax where in the callback function is called once server call is complete.
Looking for the best approach for such scenario.
Here's a simple publish subscribe model in jQuery from this blog post
var exampleHandle = function(){
//do stuff when topic is published
...
}
function subscribe(topic,handle){
$("#subscription").bind(topic,handle);
}
function publish(topic,params){
$("#subscription").trigger(topic,params)
}
function unsubscribe(topic,handle){
$("#subscription").unbind(topic,handle);
}
where you can use a simple string as a topic to subscribe or unsubscribe to the topic, and attach the handle as a callback function. The handle can also be used to unsubscribe from the topic later if necessary.
The method is based on jQuery’s trigger and bind functions. These
allow you to listen for a custom event on an element, and manually
trigger an event on an element. This provides the basic backbone for
the simple subscription model.
If an application element wants to
subscribe to a topic, they bind a handler to the “subscription
element”. This can be a designated element on the page, or just the
window element. You can also of course use different elements for
different subscriptions. Then, when something publishes to that topic,
the handler function will execute.
For publishing, a function can pass
a topic and parameters to the publish function. This calls jQuery’s
trigger to set off the event topic, passing along the parameters.
These params are passed to the handle function.
If an element wants to
cancel its subscription, they can pass the topic and handle function
to the unsubscribe method. Note that the handle has to be the same
function object that was used to originally subscribe, not a copy or
similar function. You also can use jQuery’s unbind to cancel all
subscriptions to a topic by only specifying the topic without the
handle function.