Add features to a feature layer.
Use case
An end-user performing a survey may want to add features to the map during the course of their work.
How to use the sample
Click on a location on the map to add a feature at that location.
How it works
A Feature
is added to a ServiceFeatureTable
which then pushes that new feature to the server.
- Create a
ServiceFeatureTable
from a URL. - Create a
FeatureLayer
from the service feature table. - Create a
Feature
with attributes and a location usingcreateFeatureAsync()
. - Add the feature to the table.
- Update the table on the server using
applyEditsAsync()
.
Relevant API
- Feature
- FeatureEditResult
- FeatureLayer
- ServiceFeatureTable
Tags
edit, feature, online service
Sample Code
// [WriteFile Name=AddFeaturesFeatureService, Category=EditData]
// [Legal]
// Copyright 2022 Esri.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// [Legal]
#ifdef PCH_BUILD
#include "pch.hpp"
#endif // PCH_BUILD
#include "AddFeaturesFeatureService.h"
#include "Basemap.h"
#include "Feature.h"
#include "FeatureEditResult.h"
#include "FeatureLayer.h"
#include "LayerListModel.h"
#include "Map.h"
#include "MapQuickView.h"
#include "MapTypes.h"
#include "Point.h"
#include "ServiceFeatureTable.h"
#include "SpatialReference.h"
#include "Viewpoint.h"
#include <QFuture>
#include <QMap>
#include <QMouseEvent>
#include <QUrl>
#include <QUuid>
#include <QVariant>
using namespace Esri::ArcGISRuntime;
namespace
{
// Convenience RAII struct that deletes all pointers in given container.
struct FeatureListResultLock
{
FeatureListResultLock(const QList<FeatureEditResult*>& list) : results(list) { }
~FeatureListResultLock() { qDeleteAll(results); }
const QList<FeatureEditResult*>& results;
};
}
AddFeaturesFeatureService::AddFeaturesFeatureService(QObject* parent /* = nullptr */):
QObject(parent),
m_map(new Map(BasemapStyle::ArcGISStreets, this))
{
m_map->setInitialViewpoint(Viewpoint(Point(-10800000, 4500000, SpatialReference(102100)), 3e7));
m_featureTable = new ServiceFeatureTable(QUrl("https://sampleserver6.arcgisonline.com/arcgis/rest/services/DamageAssessment/FeatureServer/0"), this);
m_featureLayer = new FeatureLayer(m_featureTable, this);
m_map->operationalLayers()->append(m_featureLayer);
}
AddFeaturesFeatureService::~AddFeaturesFeatureService() = default;
void AddFeaturesFeatureService::init()
{
// Register the map view for QML
qmlRegisterType<MapQuickView>("Esri.Samples", 1, 0, "MapView");
qmlRegisterType<AddFeaturesFeatureService>("Esri.Samples", 1, 0, "AddFeaturesFeatureServiceSample");
}
MapQuickView* AddFeaturesFeatureService::mapView() const
{
return m_mapView;
}
// Set the view (created in QML)
void AddFeaturesFeatureService::setMapView(MapQuickView* mapView)
{
if (!mapView || mapView == m_mapView)
return;
m_mapView = mapView;
m_mapView->setMap(m_map);
emit mapViewChanged();
connectSignals();
}
void AddFeaturesFeatureService::connectSignals()
{
//! [AddFeaturesFeatureService add at mouse click]
// connect to the mouse clicked signal on the MapQuickView
connect(m_mapView, &MapQuickView::mouseClicked, this, [this](QMouseEvent& mouseEvent)
{
// obtain the map point
const double screenX = mouseEvent.position().x();
const double screenY = mouseEvent.position().y();
Point newPoint = m_mapView->screenToLocation(screenX, screenY);
// create the feature attributes
QMap<QString, QVariant> featureAttributes;
featureAttributes.insert("typdamage", "Minor");
featureAttributes.insert("primcause", "Earthquake");
// create a new feature and add it to the feature table
Feature* feature = m_featureTable->createFeature(featureAttributes, newPoint, this);
m_featureTable->addFeatureAsync(feature).then(this, [this]()
{
// if add feature was successful, call apply edits
m_featureTable->applyEditsAsync().then(this, [](const QList<FeatureEditResult*>& featureEditResults)
{
// Lock is a convenience wrapper that deletes the contents of the list once we leave scope.
FeatureListResultLock lock(featureEditResults);
if (lock.results.isEmpty())
return;
// obtain the first item in the list
FeatureEditResult* featureEditResult = lock.results.first();
// check if there were errors, and if not, log the new object ID
if (!featureEditResult->isCompletedWithErrors())
qDebug() << "New Object ID is:" << featureEditResult->objectId();
else
qDebug() << "Apply edits error.";
});
});
});
//! [AddFeaturesFeatureService add at mouse click]
}