Esri Leaflet
This content has moved to Please update your bookmarks!

Editing feature layers

This sample uses the Leaflet Editable plugin (coupled with the Leaflet.Path.Drag plugin) to help users manipulate the geometry of features from a hosted feature service and pass the edits back to the server.

<!DOCTYPE html>
  <meta charset="utf-8" />
  <title>Editing feature layers</title>
  <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />

  <!-- Load Leaflet from CDN -->
  <link rel="stylesheet" href=""
  <script src=""

  <!-- Load Esri Leaflet from CDN -->
  <script src=""

  <!-- Load Esri Leaflet Vector from CDN -->
  <script src=""

    body { margin:0; padding:0; }
    #map { position: absolute; top:0; bottom:0; right:0; left:0; }

<script src=""></script>
<script src=""></script>

<div id="map"></div>

<script type="text/javascript">
    // make sure double clicking the map *only* triggers the editing workflow
    var map ='map', {
      editable: true,
      doubleClickZoom: false
    }).setView([37.345, -110.875], 5);

    L.esri.Vector.vectorBasemapLayer('ArcGIS:ChartedTerritory', {
      apikey: apiKey // Replace with your API key -

    // create a feature layer and add it to the map
    var wildfireDistricts = L.esri.featureLayer({
      url: ''

    // create a generic control to invoke editing
    L.EditControl = L.Control.extend({
      options: {
        position: 'topleft',
        callback: null,
        kind: '',
        html: ''
      // when the control is added to the map, wire up its DOM dynamically and add a click listener
      onAdd: function (map) {
        var container = L.DomUtil.create('div', 'leaflet-control leaflet-bar');
        var link = L.DomUtil.create('a', '', container);
        link.href = '#';
        link.title = 'Create a new ' + this.options.kind;
        link.innerHTML = this.options.html;
          .on(link, 'click', L.DomEvent.stop)
          .on(link, 'click', function () {
            window.LAYER =;
          }, this);
        return container;

    // extend the control to draw polygons
    L.NewPolygonControl = L.EditControl.extend({
      options: {
        position: 'topleft',
        callback: map.editTools.startPolygon,
        kind: 'polygon',
        html: '▰'

    // extend the control to draw rectangles
    L.NewRectangleControl = L.EditControl.extend({
      options: {
        position: 'topleft',
        callback: map.editTools.startRectangle,
        kind: 'rectangle',
        html: '⬛'

    // add the two new controls to the map
    map.addControl(new L.NewPolygonControl());
    map.addControl(new L.NewRectangleControl());

    // when users CMD/CTRL click an active editable feature,
    // remove it from the map and delete it from the service
    wildfireDistricts.on('click', function (e) {
      if ((e.originalEvent.ctrlKey || e.originalEvent.metaKey) && e.layer.editEnabled()) {
        // delete expects an id, not the whole geojson object

    // when users double click a graphic, toggle its editable status
    // but when deselecting via double click, pass the geometry update to the service
    wildfireDistricts.on('dblclick', function (e) {
      if (!e.layer.editEnabled()) {

    // when a new feature is drawn using one of the custom controls,
    // pass the edit to the featureLayer service
    map.on('editable:drawing:commit', function (e) {
      wildfireDistricts.addFeature(e.layer.toGeoJSON(), function (error, response) {
        if (error || !response.success) {
          console.log(error, response);

        // now that the L.esri.featureLayer instance will manage this new feature,
        // remove any temporary features from the map that were created by the Editable plugin

      // disable editing