block by maptastik 079473e19f68aa3dca19

Querying a related table in a feature service using Esri-Leaflet & Esri-Leaflet-Related

Full Screen

Just some experimentation with Esri-Leaflet. Basically, we have a feature service for our parcel data that is split into two layers: geometry and attribute data. The attribute data is a related table. Natively, Esri-Leaflet doesn’t query data from a related table. Luckily Esri-Leaflet-Related exists. It’s in beta and uses a release candidate build (I think that’s the term) of Esri-Leaflet 1.0.0, but I was able to use it to pull data from the related attribute table and make it so that when the user hovers over a parcel (geometry), an info pane shows the parcel’s address (related attribute table). When the user clicks, a table appears with more info about the parcel (related attribute table).

index.html

<html>
<head>
  <meta charset=utf-8 />
  <title>Querying a related table in feature service</title>
  <meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />

  <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">

  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.2.4/bootstrap-table.min.css">

  <script src="//code.jquery.com/jquery-1.11.0.min.js"></script>

  <!-- cool bootstrap plugin for working with tables
    ////wenzhixin.net.cn/p/bootstrap-table/docs/index.html
  -->
  <script src="//rawgit.com/wenzhixin/bootstrap-table/master/dist/bootstrap-table.min.js"></script>

  <!-- Load Leaflet from CDN-->
  <link rel="stylesheet" href="//cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
  <script src="//cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>

  <!-- Load Esri Leaflet from CDN -->
  <script src="//cdn-geoweb.s3.amazonaws.com/esri-leaflet/1.0.0-rc.6/esri-leaflet.js"></script>
  <script src="https://cdn.rawgit.com/maptastik/esri-leaflet-related/master/src/EsriLeafletRelated.js"></script>

  <style>
    body {margin:0;padding:0;}
    #map {
      position: absolute;
      top: 0;
      bottom: 0;
      right: 0;
      left: 0;
    }
    #info-pane {
      position: absolute;
      top: 10px;
      right: 10px;
      z-index: 10;
      padding: 1em;
      background: white;
    }
    .fixed-table-container {
      position: absolute;
      top: 10px;
      left: 50px;
      z-index: 10;
      padding: 1em;
      background: white;
    }
    .fixed-table-body {
      max-height: 600px;
      max-width: 400px;
    }
    #hidden {
      display:none;
    }
  </style>
</head>
<body>
<div id='my-table' class="hidden leaflet-bar table-condensed">
</div>
<div id="map"></div>
<div id="info-pane" class="leaflet-bar"></div>

<!--Loads the app-->
<script src="app.js"></script>

</body>
</html>

app.js

  //Set up map
  var map = L.map('map').setView([38.317236, -84.564147], 15);

  //Basemap
  var base = L.tileLayer('http://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> &copy; <a href="http://cartodb.com/attributions">CartoDB</a>',
    subdomains: 'abcd',
    maxZoom: 19
  }).addTo(map);

  // Add Parcel from gis.gscplanning
  var parcels = L.esri.featureLayer('http://gis.gscplanning.com/arcgis/rest/services/Parcels/FeatureServer/0', {
    simplifyFactor: 0.35,
    precision: 5,
    style: function (feature) {
      return {
        color: '#ff33ff',
        fillOpacity: 0,
        weight: 1
      }
    }
  }).addTo(map);

  var oldId;

  //info pane text
  var defaultInfoPaneText = 'Hover to Inspect<br><em>Click for more info</em>'
  document.getElementById('info-pane').innerHTML = defaultInfoPaneText;
  
  //What to do when mouse leaves a parcel
  parcels.on('mouseout', function(e){
    document.getElementById('info-pane').innerHTML = defaultInfoPaneText;
  });

  //When mouse hovers over a parcel, do the queryRelatedBasic function
  parcels.on('mouseover', queryInfoPane);

  //function that gets parcel info from a related table and then updates the info pane with the address. also, changes the color of the parcels
  function queryInfoPane(e) {
    var query = L.esri.Tasks.queryRelated(parcels).objectIds([e.layer.feature.id]).relationshipId("0").run(function(error, response, raw) {     
      parcels.resetStyle(oldId);
      oldId = e.layer.feature.id;
      document.getElementById('info-pane').innerHTML = response.features[0].properties.Complete_A;
      e.layer.bringToFront();
      parcels.setFeatureStyle(e.layer.feature.id, {
        color: '#ffff33',
        weight: 3,
        fillOpacity: 0.25
      })
    });
  }


  // fire a query when users click on a feature
  parcels.on("click", queryRelated);

  function queryRelated(evt) {
    L.esri.Tasks.queryRelated(parcels).objectIds([evt.layer.feature.id]).relationshipId("0").run(function(error, response, raw) {
      //pull the attributes out of the geoJson response
      if (response.features.length > 0) {
        var results = [];
        for (i=0; i < response.features.length; i++){
          results.push(response.features[i].properties);
        }
        $('#my-table').removeClass('hidden');
        //you can only call refresh() when loading from a url
        $('#my-table').bootstrapTable('destroy');
        $('#my-table').bootstrapTable({
          data: results,
          cache: false,
          striped: true,
          clickToSelect: true,
          columns: [{
              field: 'MapNumber',
              title: 'GIS Map ID',
              sortable: false
          }, {
              field: 'Name1',
              title: 'Owner',
              sortable: false
          }, {
              field: 'Complete_A',
              title: 'Address',
              sortable: false
          }]
        });
      }
    });
  }

  map.on("click", function(){
    //hide the table when the map is clicked
    $('#my-table').bootstrapTable('destroy');
  });