ArcGIS Runtime SDK for Qt

Edit features

ArcGIS Runtime supports editing workflows that leverage the use of features. A feature is a persisted piece of data (essentially a row in a table) that includes a geographic location (shape) as well as attributes that further describe it, such as Name, Area, Population, ZoningCode, and so on. Your app can include the ability to add and delete entire features or to make edits to existing feature geometry and attributes. If your features have attachments (images or text files, for example) or related records in another dataset, that information can be edited as well.

Features can be hosted in an online service, stored locally in a database, or saved in a map or portal item. How your features are stored affects how you make and manage edits to them in your app. For more information on features and where they come from, see Features and graphics.

Editing overview

Your apps can edit features while online (connected to the network and using data hosted online) or offline (without a network connection and using local data). You can edit features from a service, a geodatabase, or a feature collection. For an introduction see Editing. While all editing workflows are described in this topic, note that there is no difference in the code that actually makes the edits (adding, deleting, or updating features, in other words).

Features from an ArcGISFeatureTable return ArcGISFeature objects which implement the loadable pattern for increased efficiency. When fetching ArcGISFeature objects for rendering and query purposes, a minimum set of required fields is returned, such as identifiers, geometry, fields used for symbolizing, and so on. When you want to edit the feature, you must load it first, otherwise the edit operation will fail.

Note:

When querying features from an online service, you have the option to return your results as loaded features so all fields are immediately available and edits can be performed.

Feature editing is supported for a number of workflows. The developer patterns for each is described below:

The online feature service editing workflow is:

  1. Create a service feature table from a feature service using the REST endpoint (URL, in other words) to identify the features you want to work with, or open a map which already contains a service feature table via a feature layer.
  2. Perform any edits against the service feature table (add, update, and delete features and feature attachments).
  3. Apply your edits to the feature service right away.

The offline feature service editing workflow is:

  1. Generate a local runtime geodatabase using a sync-enabled feature service while the user is onlineas described in Create an offline map.
  2. Create a geodatabase feature table from the local geodatabase. If this is for a connected feature layer already in a map, then that layer will need to be switched out with a new feature layer created with this table.
  3. Perform any edits against the geodatabase feature table (add, update, and delete features and feature attachments).
  4. Synchronize your edits with the service once you have a network connection, as described in Sync offline edits.

The static feature collection editing workflow is:

  1. Create a new feature collection or open a map which already contains a feature collection via a feature collection layer.
  2. For new feature collections, create a new feature collection table and add it to the feature collection. For feature collections from a map, access a feature collection table from the feature collection.
  3. Perform any edits against the feature collection table (add, update, and delete features).
  4. For feature collections which are to be stored in the map, save the map. For feature collections to be saved as a portal item, save the feature collection as a portal item.

Create a feature table

Before you can edit features, you need to obtain feature data from a feature table.

In a connected workflow, the type of feature table you use and edit is a ServiceFeatureTable. In a disconnected workflow, the type of feature table you use and edit is a GeodatabaseFeatureTable. Both classes inherit from ArcGISFeatureTable, which itself inherits from FeatureTable.

For working with features by value, the type of table you use is FeatureCollectionTable. Feature collection tables do not contain attachments and inherit directly from FeatureTable.

The methods to add, update, and delete features are common to FeatureTable and the methods for updating attachments are provided by ArcGISFeatureTable. Therefore, all the methods you have at your disposal to edit features from a feature service are available both online and offline. The ServiceFeatureTable used in connected editing provides additional methods to apply feature edits and attachment edits back to the service. You should apply any edits to the service as soon as you have made them on your feature table.

Feature service edit capabilities

When working with features from a feature service online or offline, additional edit capabilities are defined to allow or prevent certain types of edits to features. You should check these capabilities to determine what editing capability is available. You may also need to verify ownership-based access is available for each edit you want to complete.

You can use properties on a feature table to find out what type of editing is supported.

  • Is editable: indicates if the table is editable.
  • Edit capabilities: describes the types of edits that are allowed for the table, such as adding, deleting, or updating features, for example.
A feature service might also use ownership-based access control, which means edits to particular features are only available to certain users. You can check ownership-based access using properties on the feature table.
  • Can add: whether or not the current user can add a feature to the table.
  • Can delete: whether or not the current user can delete a feature from the table.
  • Can update: whether or not the current user can edit an existing feature.

Online feature services

In an online workflow, you need a service feature table created from a feature service. If you have opened a map, you can use a feature layer and retrieve its feature table and check it is of the correct type. For new layers, you can create a service feature table with the feature service URL and then create a feature layer. Once the feature layer is in a map and displayed in a map view, features in the map extent are added to the service feature table and can be edited. As you pan and zoom the map (that is, change the map extent), more features are retrieved from the feature service and added to the service feature table. If you are not using a map or you want to pre-populate your table with a fixed set of features, use the populateFromService method.

Note:

The number of features you see when you initially visit a new area of the map is limited by the feature service's maximum record count property (the default value for this property is 1,000). Pan and zoom to query the service for more features. Once features are retrieved from the service and visible in your map, they are available in your service feature table for editing and querying.

Start with a map app such as the one described in Develop your first map app. Declare a new feature layer whose source is a service feature table created using a URL.

FeatureLayer {
    id: hospitalFeatureLayer
    featureTable: ServiceFeatureTable {
        id: hospitalFeatureTable
        url: url_HospitalFeatureTable
        credential: Credential {
            username: g_QtTeamUsername
            password: g_QtTeamPassword
        }
        // ...

Because they rely on a remote service to properly initialize their state, service feature tables use the Loadable pattern. You can load a service feature table and check its load status before adding it to the map, which allows you to handle load failure and to retry loading the table if necessary. However, if you use the feature table to create a feature layer and add that to a map or scene, the table will automatically attempt to load when the layer is displayed.

Note:

Features in a service feature table are Loadable for added efficiency; before editing your feature ensure it is loaded otherwise the edit operation will fail.

Offline feature services

In an offline workflow, you need to first generate a runtime geodatabase from a sync-enabled feature service while you have a network connection. Follow the geodatabase generation process described in Create an offline map. This process results in a geodatabase stored locally on disk. The geodatabase contains one or more feature tables, one for each service layer or service table that you requested in the geodatabase generation process. When offline, create geodatabase feature tables (GeodatabaseFeatureTable) from the geodatabase, for example, on application load. The features stored in the geodatabase tables are available for editing whether you display them in a layer or not, but in most cases you'll want to create feature layers to display them for editing. Also, consider generating an offline basemap to give the feature data some geographical context when your users edit offline.

Caution:

You can also generate a runtime geodatabase using ArcGIS for Desktop, but these geodatabases are read-only.

The following example shows how to instantiate a geodatabase object from a local geodatabase file, and from that create a feature table and a feature layer.

// create a feature layer
FeatureLayer {
    // obtain the feature table from the geodatabase by name
    featureTable: gdb.geodatabaseFeatureTablesByTableName["Trailheads"] ?
                      gdb.geodatabaseFeatureTablesByTableName["Trailheads"] :
                      null


    // create the geodatabase
    Geodatabase {
        id: gdb
        path: dataPath + "geodatabase/LA_Trails.geodatabase"


        onErrorChanged: errorMessage = error.message;
    }


    onErrorChanged: errorMessage = error.message;
}

Static feature collections

For working with static feature collections, you either need a map which already contains a feature collection layer, or you need to create a new feature collection layer.

Add layers to the map

You can display the features contained in the feature table by adding them to a feature layer in the map. Create feature layers from any feature table then add them to a map. A feature layer, once added to a map, takes care of displaying the features contained in your feature table within the map extent currently displayed. When features in the table are edited, the edits are visible right away in the associated feature layer, but not immediately committed back to the feature source.

If you declared the feature layer inside the declaration of your map, the new layer will appear in the map. If you declared it outside the map, you can append the feature layer you created to the list of operational layers in your map in a function.

operationalLayers.append(hospitalFeatureLayer);

You will be able to see features like this on your map.

Features displayed on the map.

Add features

For creating new features, it's common for an app to allow the user to click the map to specify a new feature's location. You can provide this capability by listening to a click event on your map view, which in turn will call a function for adding a new feature.

onMouseClicked: {  // mouseClicked came from the MapView
    // create attributes json for the new feature
    var featureAttributes = {"typdamage" : "Minor", "primcause" : "Earthquake"};


    // create a new feature using the mouse's map point
    var feature = featureTable.createFeatureWithAttributes(featureAttributes, mouse.mapPoint);


    // add the new feature to the feature table
    featureTable.addFeature(feature);
}

To add features to a feature table, create a new feature from geometry (for example, point, line, or polygon), create attributes for the new feature, and then call add feature. This adds the feature to a table stored locally on your device. Even if you're editing a service feature table, your edits are initially stored in a table on the client. You must explicitly apply service feature table edits to commit them to the parent feature service.

Note:

All features you add or update in a feature service should have valid geometry. Creating features with empty (null) geometry can cause unexpected issues when working with features in ArcGIS Runtime offline editing workflows.

In the QML type that hosts your app, add a property to hold a point geometry.

property var newPoint

In the onMouseClicked signal handler for the map view, get the mouse position and convert it to a point geometry.

editFeatureServiceWindowLoader.item.newPoint = mouse.mapPoint;

Create attributes for your new feature use them with the point geometry to create a new feature. Then add the feature to the feature service table.

attr = {
    "TraumaLevel" : featureTypeToAdd
};
newFeat = hospitalFeatureTable.createFeatureWithAttributes(attr, newPoint);
hospitalFeatureTable.addFeature(newFeat);

Tip:

When adding new features, it is good practice to ensure the geometry of the new feature is not null. If the location of a feature is not yet known, you may want to use an empty geometry.

Select features

In an editing app, a common workflow is for the user to choose features to edit by selecting them with a query or interactively on the map. Features in a feature layer can be selected, which results in them being highlighted in the map view. You can select features based on spatial relationships (sample points located inside the forest boundary polygon), using attribute criteria (pipes with a material_type attribute of 'pvc'), or both (parcels outside the city limits with a zoning code of 'COM'). You can also get selected features from a layer, after letting the user make an interactive or custom selection, for example.

Selected point graphics

In editing workflows, features are typically selected for tasks such as deleting or updating.

The following code snippet selects features that are within an envelope centered on the mouse position. Alternatively, you could create a buffer around the mouse position to create a round selection geometry.

function selectFeatures(mouse, unitsPerDIP) {
    // create an envelope with some tolerance and query for feature selection within that envelope
    var envelope = projectedEnvelopeFromPoint(mouse, unitsPerDIP);


    // set the envelope as the geometry for the query parameter
    params.geometry = envelope;


    // query and select the features
    if (selectedLayer === "Fire Stations") {
        fireStationFeatureLayer.selectFeaturesWithQuery(params, Enums.SelectionModeNew);
    } else if (selectedLayer === "Hospitals") {
        hospitalFeatureLayer.selectFeaturesWithQuery(params, Enums.SelectionModeNew);
    } else if (selectedLayer === "Roads") {
        roadsFeatureLayer.selectFeaturesWithQuery(params, Enums.SelectionModeNew);
    } else if (selectedLayer === "Parks") {
        parksFeatureLayer.selectFeaturesWithQuery(params, Enums.SelectionModeNew);
    } else if (selectedLayer === "Public") {
        litePublicLayer.selectFeaturesWithQuery(params, Enums.SelectionModeNew);
    }
}

You can also select specific features using the select feature method and passing in a single feature.

Update features

Feature updates include moving or reshaping a feature's geometry or making edits to attribute values. As with all editing operations the changes are not automatically committed to the features source, it is the developer's responsibility to do this.

Here, a feature is retrieved from the iterator on the FeatureLayer.selectFeatureResult property of a layer for which a selection task was run.

currentFeature  = selectFeaturesResult.iterator.next();

Then, the attribute value of the selected feature is updated.

currentFeature.attributes.replaceAttribute("TraumaLevel",newAttrText.text);
hospitalFeatureTable.updateFeature(currentFeature);

Later when edits are ready to be committed, call applyEdits on the feature table.

hospitalFeatureTable.applyEdits();

Delete features

You can delete several features from a feature table using the delete features method that accepts a list of features, or just a single feature with a call to delete feature. As with all editing operations the changes are not automatically committed to the features source, it is the developer's responsibility to do this.

hospitalFeatureTable.deleteFeature(currentFeature);

Feature attachments

Attachments are files you associate with a feature, including text, images, videos, and so on. Attachments are only available for features from an ArcGIS feature table. You might want to attach a photograph to a parcel feature, for example, to show a picture of the property. Attachments on a feature are manipulated using the following methods on the ArcGIS feature class.

MethodDescription

add attachment

Adds a new attachment to a feature

delete attachment

Deletes a single existing attachment

delete attachments

Deletes a list of existing attachments

update attachment

Updates an existing attachment

fetch attachments

Accesses the attachments for a feature

ArcGIS feature inherits from the feature class, so you can cast from feature to ArcGIS feature if needed. Prior to adding, updating or deleting features it is good practice to make sure that you have permission to perform one of these operations. This is done by using the can edit attachments property. Once you have performed your attachment edits, these are applied to the feature using the update feature method and finally the feature needs to be applied to the service by calling the apply edits method on your feature table.

The following code snippet adds the content of the file name selected with a FileDialog component, and adds the file's content as an attachment.

FileDialog {
    id: fileDialog


    function doAddAttachment(){
        if (selectedFeature.loadStatus === Enums.LoadStatusLoaded) {
            selectedFeature.onLoadStatusChanged.disconnect(doAddAttachment);
            selectedFeature.attachments.addAttachment(fileDialog.fileUrl, "application/octet-stream", fileInfo.fileName);
        }
    }


    onAccepted: {
        // add the attachment to the feature table
        fileInfo.url = fileDialog.fileUrl;
        if (selectedFeature.loadStatus === Enums.LoadStatusLoaded) {
            selectedFeature.attachments.addAttachment(fileDialog.fileUrl, "application/octet-stream", fileInfo.fileName);
        } else {
            selectedFeature.onLoadStatusChanged.connect(doAddAttachment);
            selectedFeature.load();
        }
    }
}

Related topics