Esri Leaflet

Editing feature layers

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

  <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=""></script>

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

    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) {

  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;