A WFS service provides read access to features, while a Transactional WFS (WFS-T) service adds insert, update, delete, and locking operations. A LuciadRIA WFSFeatureStore supports both: see Visualize WFS data for the read-only side of the store.

Prerequisites

WFS-T requires:

  • A store created with WFSFeatureStore.createFromCapabilities() or createFromURL(). These methods read the server’s advertised capabilities, so the store knows upfront which WFS-T operations are supported.

  • A WFS 2.0 server that advertises the operation you’re calling: Transaction for add/put/remove, LockFeature or GetFeatureWithLock for locking.

If either condition isn’t met, the corresponding method throws a ProgrammingError immediately, without sending a request.

Insert, update, and delete features

The add(), put(), and remove() methods each send a single <wfs:Transaction> request with one action: to insert, update, or delete features respectively.

The add(feature) method inserts a new feature and returns the ID assigned by the server:

const id = await store.add(feature);

The put(feature) method updates an existing feature. Its feature.id must be set. The defined properties and the geometry are sent to the server. Set a property to null to clear it. If a property is undefined, it is omitted and the server-side value remains unchanged. The same applies to feature.shape.

// Setting a property to null clears it server-side; leaving it undefined keeps the current value.
feature.properties.name = "Updated name";
await store.put(feature);

The remove(id) method deletes a feature by ID:

await store.remove(id);

Lock features for exclusive editing

If you lock features, you reserve them so that no other client can change them while you’re editing. It’s optional: some servers lock automatically as soon as an edit starts, in which case you don’t need to call lockFeatures() yourself. To find out about possible automatic locking, check the AutomaticDataLocking OWS constraint on the server’s Transaction operation.

There are two ways to acquire a lock:

  • lockFeatures(filter) locks features matching an OGC condition, without retrieving them.

  • queryWithLock(query) queries and locks the matching features in a single round-trip. Unlike lockFeatures(), it can’t report which features it failed to lock — there’s no notLockedFeatureIds on its result.

const {lock, lockedFeatureIds} = await store.lockFeatures(identifiers(["road-42"]));
const {lock, cursor} = await store.queryWithLock({filter: identifiers(["road-42"])});

Both locking methods return a lock that you can pass as an options.lock transaction option to put() or remove() to authorize the change:

await store.put(feature, {lock});

A successful put() or remove() releases only the feature it touched from the lock, as determined by the default releaseAction: "SOME" property on the transaction option. To release every feature still covered by the lock instead, pass releaseAction: "ALL". Tracking which lock covers which feature IDs is your responsibility — the store doesn’t track this for you. A lock expires automatically after its expiry (in seconds), or you can release it explicitly:

await lock.release();

Sample code to get you started

The WFS section of the LuciadRIA Data Formats sample puts all of the above together: it detects WFS-T support automatically, lets you adjust a feature’s geometry, and sends the change back to the server — acquiring a lock first when the server requires it.