Esri Leaflet

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