In this section, we will look at three classes in the OpenLayers library that we won't often work directly with, but which provide an enormous amount of functionality to most of the other classes in the library. The first two classes, Observable and Object, are at the base of the inheritance tree for OpenLayers—the so-called super classes that most classes inherit from. The third class, Collection, isn't actually a super class but is used as the basis for many relationships between classes in OpenLayers—we've already seen that the Map class relationships with layers, overlays, interactions, and controls are managed by instances of the Collection class.
Before we jump into the details, take a look at the inheritance diagram for the components we've already discussed:

As you can see, the Observable class, ol.Observable, is the base class for every component of OpenLayers that we've seen so far. In fact, there are very few classes in the OpenLayers library that do not inherit from the Observable class or one of its subclasses. Similarly, the Object class, ol.Object, is the base class for many classes in the library and itself is a subclass of Observable. Because the functionality contained in these two classes is so fundamental to the understanding of how OpenLayers works, we'll be relying on them for the rest of the book.
The Observable and Object classes aren't very glamorous. You can't see them in action and they don't do anything very exciting from a user's perspective. What they do though is provide two common sets of behaviour that you can expect to be able to use on almost every object you create or access through the OpenLayers library—Event management and Key-Value Observing (KVO).
An event is basically what it sounds like—something happening. Events are a fundamental part of how various components of OpenLayers—the map, layers, controls, and pretty much everything else—communicate with each other. It is often important to know when something has happened and to react to it. One type of event that is very useful is a user-generated event, such as a mouse click or touches on a mobile device's screen. We used this earlier in the chapter to display an overlay at the location of a mouse click. Knowing when the user has clicked and dragged on the Map class allows some code to react to this and move the map to simulate panning it. Other types of events are internal, such as the map being moved or data finishing loading. To continue the previous example, once the map has moved to simulate panning, another event is issued by OpenLayers to say that the map has finished moving so that other parts of OpenLayers can react by updating the user interface with the center coordinates or by loading more data.
Classes inheriting from ol.Observable (including ol.Object) get the following event related methods:
It is very important to pass the exact same listener and scope values to un() as were passed to on(). A common practice is to pass anonymous functions as arguments to functions such as on(), which takes function arguments. Because un() needs the exact same listener argument to work correctly, we can't use anonymous functions if we want to call un() later. However, we can store the key returned by on() and use it with unByKey(). Let's look at some code examples:
var map = new ol.Map({
target: 'map',
view: view
});This creates a Map class object, nothing new here.
map.on( 'moveend', function() {
console.log('move end event!');
});Next, we will register for the moveend
event. The moveend event is triggered by the map after it has been panned or zoomed. The function we provide will be called every time the map moves. Our code will output some text to the debug console. Because we used an inline or anonymous function, we have no way to remove our function if we no longer want to receive events. Or do we?
var key = map.on('moveend', function() {
console.log('move end event!');
});
map.unByKey(key);This code registers for the same moveend event using an anonymous function but this time we will assign the return value to key. We can then use the value assigned to key to unregister our handler.
Let's look at another way:
function onMoveEnd(event) {
console.log('moveend event 2');
}
map.on('moveend', onMoveEnd);
map.un('moveend', onMoveEnd);This block declares a function called onMoveEnd() and registers it for the moveend event. The last line unregisters it. This achieves exactly the same result as the previous code; so, what's the difference? It is mostly to accommodate different coding styles and patterns. Some people prefer to write their code a certain way, or perhaps they have to follow a particular coding style guide (see Appendix B, More details on Closure Tools and Code Optimization Techniques for more information on this), and OpenLayers provides various ways to make it easier.
What about the scope parameter? This is useful for code that is written in an Object oriented style. Here is a contrived example that illustrates how it will be used:
var MyClass = function(label) {
this.label = label;
this.onMoveEnd = function() {
console.log( this.label + ': moveend event');
}
}
var obj1 = new MyClass('Object 1');
var obj2 = new MyClass('Object 2');A simple class called MyClass is defined, which contains a single attribute, label, and a single method, onMoveEnd(). Next, two instances of this class are created with different label values. We can use the onMoveEnd() method of our instances as a function in the second parameter of the on() method. When the onMoveEnd() method is called, it will log a message to the debug console containing the value of the label attribute. Here are some examples of how this can be used:
map.on('moveend', obj1.onMoveEnd);Registering the onMoveEnd() method for the moveend event will work, but the output will be as follows:
Undefined: zoomend event
What's wrong? It turns out that this.label is not defined because the value of this is the global window object. We can correct this by passing a scope object as the third parameter to the on() function:
map.on('moveend', obj1.onMoveEnd, obj1);
map.on('moveend', obj2.onMoveEnd, obj2);Now, the output will be what we expected:
Object 1: moveend event Object 2: moveend event
We then need to use the scope to unregister for the events as follows:
map.un('moveend', obj1.onMoveEnd, obj1);
map.un('moveend', obj2.onMoveEnd, obj2);