Skip to main content
1 of 3
Lars
  • 2.2k
  • 2
  • 19
  • 33

How to get selected OL3 feature properties with Angular JS ($scope.$watch)

I want to display feature properties that have been selected in an OpenLayers3 map. I am using AngularJS and try to update the currently selected feature properties using $scope$watch.

I have a MapManager file that is used to handle all necessary OL3 operations:

// DEFAULT variables
var defaultCenter = [-2.15, 52.267];
var defaultZoom = 12;
var epsgWGS84 = 'EPSG:4326';
var epsgDefaultMapOL = 'EPSG:3857';
var defaultTarget = 'map';

// Constructor
function MapManager(target, center, zoom){
    // check if parameters are set - use defaults otherwise
    if(!target){
        target = defaultTarget;
    }
    if(!center){
        center = defaultCenter;
    }
    if(!zoom){
        zoom = defaultZoom;
    }
    this.map = this.initMap(target, center, zoom);
    this.selectedFeature = null;
}


// Getter
MapManager.prototype.getSelectedFeature = function(){
    return this.selectedFeature;
};

// get feature properties from selected feature (filtered properties - e.g. no geometry)
MapManager.prototype.getSelectedFeatureProperties = function(){
    //var displayProperties = [];
    var displayProperties = {};
    if(this.getSelectedFeature() != null){
        $.each(this.getSelectedFeature().getProperties(), function(key, value) {
            // skip the geometry property
            if(key != "geometry"){
                displayProperties[key] = value;
            }
        });
    }
    return displayProperties;
}

// Setter
MapManager.prototype.setSelectedFeature = function(feature){
    this.selectedFeature = feature;
};

// Geojson with lines
var geojsonObject = {
    'type': 'FeatureCollection',
    'crs': {
        'type': 'name',
        'properties': {
            'name': 'EPSG:4326'
        }
    },
    'features': [
        {
            'type': 'Feature',
            'properties': {
                'prop1': 'feature1',
                'prop2': 'Blub'
            },
            'geometry': {
                'type': 'LineString',
                'coordinates': [
                    [-2.176, 52.266], [-2.166, 52.276]
                ]
            }
        },
        {
            'type': 'Feature',
            'properties': {
                'prop1': 'feature2',
                'prop2': 'Test'
            },
            'geometry': {
                'type': 'LineString',
                'coordinates': [
                    [-2.132, 52.272], [-2.145, 52.258]
                ]
            }
        }
    ]
};

// create vector source with geojson
var vectorSource = new ol.source.Vector({
    features: (new ol.format.GeoJSON()).readFeatures(geojsonObject, {
        dataProjection: 'EPSG:4326',
        featureProjection: 'EPSG:3857'
    })
});


// ### Create layers
// create osm layer
function createLayerWebOSM(){
    return new ol.layer.Tile({
        source: new ol.source.OSM(),
        projection: epsgDefaultMapOL
    });
}

// create vector layer (using geojson vector source)
var vectorLayer = new ol.layer.Vector({
    source: vectorSource
});


// Initialize map
MapManager.prototype.initMap = function(target, center, zoom){
    this_ = this;
    var map = new ol.Map({
        target: target,
        layers: [createLayerWebOSM(), vectorLayer],
        view: new ol.View({
        center: ol.proj.transform(center, epsgWGS84, epsgDefaultMapOL),
        zoom: zoom
      })
    });
    
    // make vector layer selectable
    vectorLayer.set('selectable', true);
    
    map.addInteraction(new ol.interaction.Select({
        layers: function(layer) {
            return layer.get("selectable") == true;
        }
    }));
    
    
    // add click interaction
    map.on("click", function(e) {
        map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
            this_.setSelectedFeature(feature);
        });
    });
    return map;
}

When a feature is clicked on the map it is stored and can be accessed with an according getter which is watched in the Angular controller:

var app = angular.module('myApp', []);

// Controller
app.controller('appController', function($scope, $q){
    $scope.mapManager = new MapManager();
    $scope.selectedFeatureProperties = {};
    
    // watch if the selected feature changes
    $scope.$watch(function($scope) {
        //return $scope.mapManager.getSelectedFeatureProperties();
        return $scope.mapManager.getSelectedFeature();
    },
    function(newFeature, oldFeature, $scope) {
        console.log("change detected...");
        $scope.selectedFeatureProperties = $scope.mapManager.getSelectedFeatureProperties();
    }, true);
    
});

I want to display the properties of the currently selected feature in a table:

<div id="main" data-ng-controller="appController">
    <!-- table with selected feature inforamtion -->
    <h4> Selected Feature Properties </h4>
    <table>
        <tr>
            <th> Property </th>
            <th> Value </th>
        </tr>
        <tr ng-repeat="(property, value) in selectedFeatureProperties">
            <td>{{ property }}</td>
            <td>{{ value }}</td>
        </tr>
    </table>
        
    <div id='map'></div>
</div>

It seems that the change is ignored.

You can see the essential part of the code at this JSFiddle. Some logs indicate that the selectedFeature variable is actually changing...

What am I doing wrong? Is there an easier way to do this (instead of using $scope$watch)?

Lars
  • 2.2k
  • 2
  • 19
  • 33