I am using OpenLayers to view features from a layer from GeoServer.

I use WMTS to display the layer when the zoom is within a certain range. I use a WMS query to look up the feature id, and other attributes, of a feature when the user clicks the map.

What I would like to be able to do is to change the values for some of the additional attributes associated with the feature that was clicked on.

From what I've read, it seems that I should be using WFS-T to update the feature. Given only the id of a feature, the name of an attribute to be updated, and the updated value for that attribute, how would I update the value through WFS-T?

Note 1: I see that the WFS class from ol/format/WFS has a method: writeTransaction, which I believe is what I should be using. However, it is not clear to me how to get the Feature object given only the id of the feature.

Here is the code that I have so far:

const WMTSMINZOOM = 14;
const WMTSMAXZOOM = 22;
const layerName = "db:TEST1";
const WFSREQUESTPREFIX = "http://localhost:8080/geoserver/ows?service=wfs&version=2.0.0" +
                     "&request=GetFeature&typename=" + layerName +

var parser = new WMTSCapabilities();
var map;

var wmsSource = new TileWMS({
url: 'http://localhost:8080/geoserver/ows?SERVICE=WMS&',
params: {'LAYERS': layerName},  // bbox can be set in params?
serverType: 'geoserver',
crossOrigin: 'anonymous'

fetch('http://localhost:8080/geoserver/gwc/service/wmts?REQUEST=GetCapabilities').then(function(response) {
    return response.text();
}).then(function(text) {
    var result = parser.read(text);
    var options = optionsFromCapabilities(result, {
        layer: layerName,
        matrixSet: 'EPSG:3857'

    map = new Map({
        target: 'map',
        layers: [
            new TileLayer({
                source: new OSM(),
                opacity: .7
            new TileLayer({
                opacity: 1,
                source: new WMTS((options))
        view: new View({
            center: [0, 0],
            zoom: 1

    map.on("moveend", function(event) {
        var theMap = event.map;
        var zoomLevel = theMap.getView().getZoom();
        var wmtsLayer = theMap.getLayers().getArray()[1];
        if (zoomLevel >= WMTSMINZOOM && zoomLevel <= WMTSMAXZOOM) {
        } else {

    map.on('singleclick', function(event) {
        document.getElementById('info').innerHTML = '';
        var viewResolution = map.getView().getResolution();
        var url1 = wmsSource.getGetFeatureInfoUrl(
            event.coordinate, viewResolution, 'EPSG:3857',{'INFO_FORMAT': 'text/html'});
        if (url1) {
            document.getElementById('info').innerHTML = 
                '<iframe seamless src="' + url1 + '"></iframe>';

        var url2 = wmsSource.getGetFeatureInfoUrl(
            event.coordinate, viewResolution, 'EPSG:3857',{'INFO_FORMAT': 'application/json'});
        if (url2) {
            fetch(url2).then(function(response) {
                return response.json()
            }).then(function(p) {
                // Removing any existing selection layers

                if (map.getLayers().getArray().length > 2) {
                    var rLayer = map.getLayers().getArray()[2];

                // Get new vector layer using WFS
                var id = p["features"][0]["id"];
                var wfsRequest = WFSREQUESTPREFIX + "&featureID=" + id;

                var vectorSource = new VectorSource({
                    format: new GeoJSON(),
                    url: wfsRequest
                var vectorLayer = new VectorLayer({
                    source: vectorSource,
                    style: new Style({
                        stroke: new Stroke({
                            color: 'rgba(0, 0, 255, 1.0)',
                            width: 2


Note 2: I see that VectorSource has a method getFeatures(), and, since I already have a vector source for a layer containing the feature clicked on, I figured I could use that method to get the Feature object that I want to update. However, when I called getFeatures() on my var vectorSource I get an array of size 0.

  • In regards to my second note; I realized that the reason that I was getting an array of 0 is that at the time that I called getFeatures() the feature had not yet been loaded; if I add to the vector source: vectorSource.on('addfeature', function(f) {…}); I do indeed get a Feature object for the feature. I might be able to figure out how to use writeTransaction(…) now; I will update if I do.
    – B. Jones
    Commented Oct 17, 2018 at 13:33

1 Answer 1


I found a solution:

const WFSREQUESTPREFIX = "http://localhost:8080/geoserver/ows?service=wfs&version=2.0.0" +
                         "&request=GetFeature&typename=" + fullLayerName +
// fullLayerName is layerPrefix:layerName

var wfsRequest = WFSREQUESTPREFIX + "&featureID=" + id;
var vectorSource = new VectorSource({
    format: new GeoJSON(),
    url: wfsRequest
vectorSource.on('addfeature', function(f) {  // vectorSource should have only a single feature
    f.feature.set(propertyName, newValue);
    f.feature.setGeometryName("geom");  // do this if geometry isn't named 'geometry'
    var wfs = new WFS({});
    var transaction = wfs.writeTransaction(null, [f.feature], null, {
        featureNS: namespaceURI,
        featurePrefix: layerPrefix,
        featureType: layerName,
        srsName: srs
    var data = new XMLSerializer().serializeToString(transaction);

        type: "POST",
        url: "http://localhost:8080/geoserver/wfs",
        data: data,
        contentType: "text/xml"
  • Hi can you post your complete code and the demo if possible?
    – gameon67
    Commented Feb 21, 2020 at 0:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.