Esri Leaflet

Editing feature layers

This sample uses Leaflet Draw to help edit the geometry of features in a hosted feature service.

<!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 (not latest version due to dependencies) -->
  <link rel="stylesheet" href="" />
  <script src=""></script>

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

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

<!-- Leaflet Draw -->
<script src=""></script>
<link rel="stylesheet" href="">

  #info-pane {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 400;
    padding: 1em;
    background: white;
    text-align: right;

  #form {
    display: none;

<div id="map"></div>
<div id="info-pane" class="leaflet-bar">
  <label id="greeting">
    Let's edit!
  <form action="#" id="form">
    <label for="PEDDISTRIC">
      Pedestrian District Name<br>
      <input id="PEDDISTRIC" type="text" value="" name="PEDDISTRIC"><br>
    <label for="TRANPLANID">
      Transportation Plan Id<br>
      <input id="TRANPLANID" type="text" value="" name="TRANPLANID" disabled="disabled">

  // create the map
  var map ='map').setView([45.512, -122.619], 12);

  // add our feature layer to the map
  var pedestrianDistricts = L.esri.featureLayer({
    url: ''

  // variable to track the layer being edited
  var currentlyEditing;
  var currentlyDeleting = false;

  // create a feature group for Leaflet Draw to hook into for delete functionality
  var drawnItems = L.featureGroup();

  // track if we should disable custom editing as a result of other actions (create/delete)
  var disableEditing = false;

  // start editing a given layer
  function startEditing (layer) {
    document.getElementById('PEDDISTRIC').value =;
    // read only
    document.getElementById('TRANPLANID').value =;
    if (!disableEditing) {
      currentlyEditing = layer;

  // stop editing a given layer
  function stopEditing () {
    // if a layer is being edited, finish up and disable editing on it afterward.
    if (currentlyEditing) {
    currentlyEditing = undefined;

  function handleEdit (layer) {
    // convert the layer to GeoJSON and build a new updated GeoJSON object for that feature = document.getElementById('PEDDISTRIC').value;
      type: 'Feature',
      geometry: layer.toGeoJSON().geometry,
    }, function (error, response) {
      if (error) {


  function displayAttributes () {
    document.getElementById('greeting').innerHTML = null;
    document.getElementById('form').style.display = 'block';

  function displayGreeting () {
    document.getElementById('greeting').innerHTML = 'Lets edit!';
    document.getElementById('form').style.display = 'none';

  // when the map is clicked, stop editing
  map.on('click', function (e) {

  // when a pedestrian district is clicked, stop editing the current feature and edit the clicked feature
  pedestrianDistricts.on('click', function (e) {
    if (!currentlyDeleting) {
    // make sure map click event isn't fired. (seems like a bug)

  // when pedestrian districts start loading (because of pan/zoom) stop editing
  pedestrianDistricts.on('loading', function () {

  // when new features are loaded clear our current guides and feature groups
  // then load the current features into the guides and feature group
  pedestrianDistricts.on('load', function () {
    // wipe the current layers available for deltion and clear the current guide layers.

    // for each feature push the layer representing that feature into the guides and deletion group
    pedestrianDistricts.eachFeature(function (layer) {

  // create a new Leaflet Draw control
  var drawControl = new L.Control.Draw({
    edit: {
      featureGroup: drawnItems, // allow editing/deleting of features in this group
      edit: false // disable the edit tool (since we are doing editing ourselves)
    draw: {
      circle: false, // disable circles
      marker: false, // disable polylines
      polyline: false, // disable polylines
      polygon: {
        allowIntersection: false, // polygons cannot intersect thenselves
        drawError: {
          color: 'red', // color the shape will turn when intersects
          message: '<strong>Oh snap!<strong> you can\'t draw that!' // message that will show when intersect

  // add our drawing controls to the map

  // when we start using creation tools disable our custom editing
  map.on('draw:createstart', function () {
    disableEditing = true;

  // when we start using deletion tools, hide attributes and disable custom editing
  map.on('draw:deletestart', function () {
    disableEditing = true;
    currentlyDeleting = true;

  // listen to the draw created event
  map.on('draw:created', function (e) {
    // add the feature as GeoJSON (feature will be converted to ArcGIS JSON internally)
    disableEditing = false;

  // listen to the draw deleted event
  map.on('draw:deleted', function (e) {
    var delArray = [];
    e.layers.eachLayer(function (layer) {
      var id =;
    pedestrianDistricts.deleteFeatures(delArray, function (error, response) {
      if (error) {
        console.log(error, response);
    disableEditing = false;
    currentlyDeleting = false;