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.selectedFeatureProperties = {prop1: "initialValue"};
}
// Getter for feature properties
MapManager.prototype.getSelectedFeatureProperties = function(){
return this.selectedFeatureProperties;
};
// Setter for feature properties
MapManager.prototype.setSelectedFeatureProperties = function(feature){
var this_ = this;
console.log("setting selected feature properties...");
var displayProperties = {};
if(feature != null){
$.each(feature.getProperties(), function(key, value) {
// skip the geometry property
if(key != "geometry"){
displayProperties[key] = value;
}
});
}
console.log(displayProperties);
this.selectedFeatureProperties = displayProperties;
}
// some 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){
var 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) {
console.log("new feature selected -> ");
console.log(feature);
this_.setSelectedFeatureProperties(feature);
console.log("new feature properties -> ");
console.log(this_.getSelectedFeatureProperties());
});
});
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() {
return $scope.mapManager.getSelectedFeatureProperties();
//return $scope.mapManager.getSelectedFeature();
},
function(newFeature, oldFeature) {
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
)?
EDIT: In the MapManager I am now saving the feature properties (selectedFeatureProperties
) directly and not the ol.Feature itself. I tried $watch
and $watchCollection
with and without true/false as last parameter but the listener is not called when the selectedFeatureProperties are changing... If I am understanding the third parameter correctly in my case it should not matter if it is true or false because the reference of the selectedFeatureProperties and the values of the properties are both changing?
Moreover I tried to pass the watchExpression as String
"mapManager.getSelectedFeatureProperties()"
or as a function
function(){
return $scope.mapManager.getSelectedFeatureProperties();
},
but that did not change anything. I adjusted the JSFiddle with some comments so you can see what I tried...