I am trying to reduce the number of event listeners attached to my collaborative models. In order to do this, I have started listening to the ObjectChanged event instead of specific event types and delegating to other handlers. However it doesn't look like the ObjectChanged event is being bubbled properly for the ValuesAdded/ValuesRemoved changes on CollaborativeLists.
function onObjectChanged(e)
{
log('Changed: ', e);
}
// Placeholder, called when we load our doc through the realtime api.
function onDocLoaded(doc)
{
var docModel = doc.getModel();
var docRoot = docModel.getRoot();
console.log('Drive document loaded: ', window.performance.now());
if (docRoot.has('testMap'))
{
docRoot.delete('testMap');
}
docRoot.set('testMap', docModel.createMap());
var testMap = docRoot.get('testMap');
console.assert(testMap, 'Test map required');
docRoot.addEventListener(gapi.drive.realtime.EventType.OBJECT_CHANGED, onObjectChanged);
var testList = docModel.createList();
testMap.set('testList', testList);
console.assert(testList, 'Test list required');
setTimeout(function ()
{
console.log('Begin Push');
testList.push('This is a test string');
console.log('End Push');
}, 1000);
}
The code above is run on doc load and demonstrates the problem. In this case, I would expect two ObjectChanged events to be fired (first for the list being set on the map and second for the string push into the list). The first event fires correctly, however the list push does not trigger an ObjectChanged event on either the 'docRoot' or the 'testMap'. As both of these are ancestors of the testList an event should be bubbled to them (based on https://developers.google.com/drive/realtime/handle-events#event_bubbling).
The ObjectChanged event however IS fired on the testList, so it looks like there is an issue with only the bubbling portion.
Is there a way of ensuring that the event bubbling will occur? Additionally, for events that are bubbling up, is there a way to stop bubbling partway?
Related
I searched quite a bit to find out the correct way to remove event listeners in Cesium. I believe the confusion I have is around whether to treat Cesium events as regular dom events (due to a lack of knowledge about events in general in javascript). I am creating a screen space event like below:
var handler = new Cesium.ScreenSpaceEventHandler(canvas);
handler.setInputAction(function (movement) {
var picked = scene.pick(movement.endPosition);
if (Cesium.defined(picked) && picked.id === someEntity) {
labelEntity.position = someEntity.position;
labelEntity.label.show = true;
} else {
labelEntity.label.show = false;
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
My question is, how can I remove this event? Is handler.destroy() removes all the event listeners associated with handler, or do I specifically have to remove event listeners by pointing to the cesium map dom element and calling removeEventListener on it? If that's the case, what parameters should be passed to removeEventListener?
The parameters for removeInputAction are just the type and optionally the modifer, and it looks like you're not using the modifier (SHIFT key, ALT key etc.)
So for the code you posted above, the removal would be:
handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
I'd like to fire an event in the Chrome Debugger. I'm not sure how to go about doing that. Also, I'd like to know how to fire a custom event that takes arguments.
In the console:
1) Select the element
For a particular element: (i.e. selector = ".edit-list-button")
var element = document.querySelector(selector)
For the whole document
var element = document.getElementsByTagName("body")[0]
2) Create the event
Without arguments:
var event = document.createEvent("Event")
With arguments: (Where data can be any object including a simple string)
var event = new CustomEvent(EVENT_NAME, { detail: DATA })
3) Initialize the event
event.initEvent(EVENT_NAME, true, true)
4) Fire the event
element.dispatchEvent(event)
How can I access to an object who fires an eventListener event?
Let's say I have a mc:
var element = new MovieClip();
which has an eventlistener:
element.addEventListener(MouseEvent.CLICK, elementEventHandler);
And then, in the event handler, I want to add something to my mc:
function elementEventHandler(event:MouseEvent):void
{
var b1:balloon = new balloon("ballon1"); //this is another class.
event.target.addChild(b1);//this doesn't work.
}
So that is what I want to achieve... Recover the object who fired the event and then do crazy things with it (in this example, add another object in it).
If anybody has any idea, thanks in advance!
pd: yes, I know I can directly use the var element in this snippet, but in the real code I'm generating the mcs in a loop, according to a xml file.
function elementEventHandler(event:MouseEvent):void
{
// use the as-operator to cast the target into the class you need
var element:DisplayObjectContainer = e.target as DisplayObjectContainer;
// if the cast fails, element will be null, then we bail
if(!element) return;
// then, create your child and add it
var b1:balloon = new balloon("ballon1");
element.addChild(b1);
}
The reason you're getting an error is probably that the event is not coming directly from element but instead from one of its descendant objects.
"click" is a bubbling event.
Check out event flow in the DOM Level 3 Events spec to understand how the capture, target, and bubbling phases work:
http://www.w3.org/TR/DOM-Level-3-Events/#dom-event-architecture
So here's what I would do:
function elementEventHandler(event:MouseEvent):void
{
if (event.target != event.currentTarget)
// If event is not from "element", ignore it.
return;
...
}
I've been reading the Google Maps API docs to see if it's possible to tell the difference between a system event vs. a user one?
For example, the zoom_changed event gets triggered when you use methods like setZoom, fitBounds, etc, which in my implementation is unsavoury, as I just want to know when the user actually changes the zoom level.
Unfortunately, the click event is only fired on the map itself, not the controls, so you can't rely on that method to help detect the users input.
Ideas?
Although I haven't been able to solve this using the Google Maps API, I have created a workaround which involves me calling this method before I change the map zoom or positioning without user interaction:
MapGraph.prototype.systemMove = function() {
var _this = this;
this.isMoving = true;
return setTimeout(function() {
return _this.isMoving = false;
}, 500);
};
And my event bindings look like this:
google.maps.event.addListener(this.map, 'dragend', function(event) {
if (!_this.isMoving) return _this.mapChanged();
});
Not perfect, but it does work.
Would love to see any other implementations though.
You may also consider an alternate solution I proposed in this Stack Overflow answer, which does not rely on mouse events to recognize user-initiated changes.
Instead of trying to recognize user events, add a flag to the map whenever a programmatic change is initiated with setZoom or fitBounds.
map.systemChange = true
map.setZoom()
Then check for (and reset) the flag in the event listener.
map.addListener('zoom_changed', function () {
if (map.systemChange) {
map.systemChange = false // Reset the flag for a system-initiated event
} else {
// Handle the user-initiated event
}
});
I want to add and remove the same event for Google map.
because I have attached a Listener to 'moveend' event on map , so event a big infoWindow opens , then also 'moveend' event occures ,which I don't want to run for this thing.
Any idea how can I turn ON and OFF 'moveend' event Listener ?
You can remove an event listener but you have to pass the exact listener returned when you added one.
e.g.
//add moveend listener
var moveendListener = GEvent.addListener(source, "moveend", yourfunction);
//remove moveend listener
GEvent.removeListener(moveendListener);
or
//remove all listeners associated with an event
GEvent.clearListeners(source, "moveend") ;
EDIT: another option is to have the function the listener calls behave differently under different conditions.
e.g.
function moveendHandler() {
if (isWhateverActive()) return;
//code to run if whatever is not active
}