4

I've been trying to build my own WFS-T and followed the tutorial from https://medium.com/@goldrydigital/wfs-t-with-openlayers-3-16-6fb6a820ac58. I have copied the code as closely as possible. The code is supposed to draw a point, line, or polygon when I click on the button and save it to my PostGIS database. Here is the code:

<! DOCTYPE=html>
<html>
    <head>
        <link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css">
        <! This is how he does his buttons >
        <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
        <style>
         .map {
          height: 100%;
          width: 100%;
         }
        </style>
        <script src="https://openlayers.org/en/v4.6.4/build/ol.js" type="text/javascript"></script>
        <script src="http://code.jquery.com/jquery-1.11.0.js"></script>
        <script src="https://code.getmdl.io/1.1.3/material.js"></script>
        <title>OpenLayers example</title>
    </head>
    <body>
        <div id="map" class="map"></div>
        <button id="btnPoint" class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored">
        <i class="material-icons">add_location</i>
        </button>
        <button id="btnLine" class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored">
        <i class="material-icons">timeline</i>
        </button>
        <button id="btnArea" class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored">
        <i class="material-icons">signal_cellular_null</i>
        </button>
        <button id="btnEdit" class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored">
        <i class="material-icons">build</i>
        </button>
        <button id="btnDelete" class="mdl-button mdl-js-button mdl-button--fab mdl-button--colored">
        <i class="material-icons">delete</i>
        </button>
        <! And now for the script!>

        <script type="text/javascript">
        var formatWFS = new ol.format.WFS();

        var formatGML = new ol.format.GML({
            featureNS: 'http://localhost:8080/geoserver/geolytix/',
            featureType: 'wfs_geom',
            srsName: 'EPSG:3857'
            });

        var xs = new XMLSerializer();

        var sourceWFS = new ol.source.Vector({
            loader: function (extent) {
            $.ajax('http://localhost:8080/geoserver/geolytix/ows?', {
            type: 'GET',
            data: {
                service: 'WFS',
                version: '1.1.0',
                request: 'GetFeature',
                typename: 'wfs_geom',
                srsname: 'EPSG:3857',
                bbox: extent.join(',') + ',EPSG:3857'
            }
            }).done(function (response) {
            sourceWFS.addFeatures(formatWFS.readFeatures(response));
            });
            },
            strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ()),
            strategy: ol.loadingstrategy.bbox,
            projection: 'EPSG:3857'
            });

        var layerWFS = new ol.layer.Vector({
        source: sourceWFS
        });

        var interaction;

        var interactionSelectPointerMove = new ol.interaction.Select({
            condition: ol.events.condition.pointerMove
            });

        var interactionSelect = new ol.interaction.Select({
            style: new ol.style.Style({
            stroke: new ol.style.Stroke({
            color: '#FF2828'
            })
            })
            });

        var interactionSnap = new ol.interaction.Snap({
            source: layerWFS.getSource()
            });

// The CartoDB map is working, but I think I'll use OSM as it looks better anyway.

        var map = new ol.Map({
        target: 'map',
        controls: [],
        interactions: [
        interactionSelectPointerMove,
        new ol.interaction.MouseWheelZoom(),
        new ol.interaction.DragPan()
        ],
        layers: [
        new ol.layer.Tile({
            source: new ol.source.OSM({
                url: 'https://cartodb-basemaps-{a-d}.global.ssl.fastly.net/dark_nolabels/{z}/{x}/{y}.png',
                opaque: false,
                attributions: []
            })
        }),
        layerWFS
        ],
        view: new ol.View({
        center: ol.proj.fromLonLat([-1.7, 53.2]),
        zoom: 6
        })
        });

// wfs-t <DON'T UNCOMMENT THIS LINE!>
        var dirty = {};
        var transactWFS = function (mode, f) {
        var node;
        switch (mode) {
        case 'insert':
            node = formatWFS.writeTransaction([f], null, null, formatGML);
            break;
        case 'update':
            node = formatWFS.writeTransaction(null, [f], null, formatGML);
            break;
        case 'delete':
            node = formatWFS.writeTransaction(null, null, [f], formatGML);
            break;
    }
    var payload = xs.serializeToString(node);
    $.ajax('http://localhost:8080/geoserver/geolytix/ows', {
        type: 'POST',
        dataType: 'xml',
        processData: false,
        contentType: 'text/xml',
        data: payload
    }).done(function() {
        sourceWFS.clear();
    });
    };

$('button').click(function () {
    $(this).siblings().removeClass('btn-active');
    $(this).addClass('btn-active');
    map.removeInteraction(interaction);
    interactionSelect.getFeatures().clear();
    map.removeInteraction(interactionSelect);

    switch ($(this).attr('id')) {

        case 'btnEdit':
            map.addInteraction(interactionSelect);
            interaction = new ol.interaction.Modify({
                features: interactionSelect.getFeatures()
            });
            map.addInteraction(interaction);
            map.addInteraction(interactionSnap);
            dirty = {};
            interactionSelect.getFeatures().on('add', function (e) {
                e.element.on('change', function (e) {
                    dirty[e.target.getId()] = true;
                });
            });
            interactionSelect.getFeatures().on('remove', function (e) {
                var f = e.element;
                if (dirty[f.getId()]) {
                    delete dirty[f.getId()];
                    var featureProperties = f.getProperties();
                    delete featureProperties.boundedBy;
                    var clone = new ol.Feature(featureProperties);
                    clone.setId(f.getId());
                    transactWFS('update', clone);
                }
            });
            break;

        case 'btnPoint':
            interaction = new ol.interaction.Draw({
                type: 'Point',
                source: layerWFS.getSource()
            });
            map.addInteraction(interaction);
            interaction.on('drawend', function (e) {
                transactWFS('insert', e.feature);
            });
            break;

        case 'btnLine':
            interaction = new ol.interaction.Draw({
                type: 'LineString',
                source: layerWFS.getSource()
            });
            map.addInteraction(interaction);
            interaction.on('drawend', function (e) {
                transactWFS('insert', e.feature);
            });
            break;

        case 'btnArea':
            interaction = new ol.interaction.Draw({
                type: 'Polygon',
                source: layerWFS.getSource()
            });
            interaction.on('drawend', function (e) {
                transactWFS('insert', e.feature);
            });
            map.addInteraction(interaction);
            break;

        case 'btnDelete':
            interaction = new ol.interaction.Select();
            interaction.getFeatures().on('add', function (e) {
                transactWFS('delete', e.target.item(0));
                interactionSelectPointerMove.getFeatures().clear();
                interaction.getFeatures().clear();
            });
            map.addInteraction(interaction);
            break;

        default:
            break;
    }
});
</script>
</body>
</html>

I have some outdated comments (like the one about OSM)- just ignore those.

I have checked the log and I am getting this error: ERROR [geoserver.ows] - org.geoserver.wfs.WFSException: No such feature type http://localhost:8080/geoserver/geolytix/:wfs_geom.

  • what is not working? what request is sent to GeoServer? what response is returned? what error messages do you see in the log file? – Ian Turton Mar 19 '18 at 8:41
  • Sorry, I should've been less vague. It's the draw tool that's not working. I know that when I click the point, line, or polygon button it is supposed to draw it on the map and save it to my PostGIS database. Right now it acts like it's going to draw, but clicking on the map does nothing when I'm drawing a point and it only briefly draws a line or polygon that disappears when I finish. I'm not a programmer by any means, just savvy enough to understand the code. How do I tell what is being sent to Geoserver or what response is being returned? I could try to find the log file later. – Ryan Norton Mar 19 '18 at 16:13
  • Okay, the error message has been added to my question! – Ryan Norton Mar 19 '18 at 21:23
  • can u please elaborate the way you published your layer in geoserver. I am still confused with the bbox and wfst service – Ashutosh Mishra Apr 10 at 17:10
3

Yay, I solved the problem: I just needed to shorten the namespace at var formatGML = new ol.format.GML({ featureNS: 'http://localhost:8080/geoserver/geolytix', featureType: 'wfs_geom', srsName: 'EPSG:3857' });

to just

var formatGML = new ol.format.GML({
        featureNS: 'geolytix',
        featureType: 'wfs_geom',
        srsName: 'EPSG:3857'
        });

and it works great!

  • It problem is solved. Mark it as accepted answer. – neogeomat Mar 20 '18 at 3:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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