[GIS] OpenLayers 3: How to check if vector source is ready

openlayers

ol.source.getState() doesn't seem to be reliable. When I call it on a vector source it returns ready, but the features are not available yet. Code looks like this:

var vectorSource = new ol.source.Vector({
  url: 'world.topo.json',
  format: new ol.format.TopoJSON()
});

// ... init map with vectorSource

console.log(vectorSource.getState()); // returns "ready"
console.log(vectorSource.getFeatureById("US")); // returns null

Any other way to see if a vector source is ready?

Best Answer

You can provide your own loader function and set some custom listeners, as it follows:

var source = new ol.source.Vector({
    loader: function(){
        var url = '....../data/json/world-110m.json';
        var format = new ol.format.TopoJSON();
        var source = this;

        //dispatch your custom event
        this.set('loadstart', Math.random());

        getJson(url, '', function(response){

            if(Object.keys(response).length > 0){
                var features = format.readFeatures(response, {
                    featureProjection: 'EPSG:3857'
                });
                source.addFeatures(features);
                //dispatch your custom event
                source.set('loadend', Math.random());
            }
        });
    }
});

Set some custom listeners:

//custom source listener
source.set('loadstart', '');
source.set('loadend', '');

source.on('change:loadstart', function(evt){
    console.info('loadstart');
});
source.on('change:loadend', function(evt){
    console.info('loadend');
});

And a xhr function:

var getJson = function(url, data, callback) {

    // Must encode data
    if(data && typeof(data) === 'object') {
        var y = '', e = encodeURIComponent;
        for (x in data) {
            y += '&' + e(x) + '=' + e(data[x]);
        }
        data = y.slice(1);
        url += (/\?/.test(url) ? '&' : '?') + data;
    }

    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open("GET", url, true);
    xmlHttp.setRequestHeader('Accept', 'application/json, text/javascript');
    xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xmlHttp.onreadystatechange = function () {
        if (xmlHttp.readyState != 4){
            return;
        }
        if (xmlHttp.status != 200 && xmlHttp.status != 304){
            callback('');
            return;
        }
        callback(JSON.parse(xmlHttp.response));
    };
    xmlHttp.send(null);
};

Working demo.