Has anyone had success integrating the Javascript API (4.6) with Drupal 7x?

899
1
Jump to solution
03-13-2018 09:04 AM
StevePeralta
New Contributor II

I was getting a "dojo.js:24 Error: multipleDefine" and then I moved "<script defer src="https://js.arcgis.com/4.6/"></script>" to just before </body>. It got rid of the error, but my map still wasn't showing up. I was bringing in the map Javascript from a separate js file.

I wrote a custom Drupal module to handle it all.

Any help appreciated.

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
StevePeralta
New Contributor II

Okay, I will answer my own question after a few days of toiling over this. Drupal 7 is not friendly to the DOM and blasts it from left and right with all kinds of stuff, so the key is to get the Esri scripts and your custom scripts loaded at the same time which, for Drupal, means in the same file. There are other ways of doing this, but not without a lot of Drupal headaches. So!

1. Create your Drupal module. I created a module called "find_my_leg" which is short for "Find My Legislator." Directory/file structure looks like this:

  • modules/custom/find_my_leg
  • modules/custom/find_my_leg/find_my_leg.info
  • modules/custom/find_my_leg/find_my_leg.module
  • modules/custom/find_my_leg/theme
  • modules/custom/find_my_leg/theme/theme.inc
  • modules/custom/find_my_leg/theme/js/findmyleg.js
  • modules/custom/find_my_leg/theme/templates
  • modules/custom/find_my_leg/theme/templates/find_my_leg_page.tpl.php

    2. Write your map code. The only three files I'll provide code for here are "find_my_leg_page.tpl.php", "findmyleg.js," and "find_my_leg.module." The others are out of the scope of this post. Check Drupal 7 docs for more info.

-------------------------------

find_my_leg_page.tpl.php

<link rel="stylesheet" href="https://js.arcgis.com/4.6/esri/css/main.css">
<script defer src="https://js.arcgis.com/4.6/"></script>
<script defer src="/sites/all/modules/custom/find_my_leg/theme/js/findmyleg.js"></script>
<!-- Replace these with your own styles -->
<style>

main#main-content.main-content{
width: 100%;
margin-top: -50px;
}

#viewDiv {
 border: 1px solid #ccc;
 padding: 0px;
 margin: 0;
 height: 600px;
 width: 100%;
}

.findLegContainer {
 display: grid;
 grid-template-columns: 60px auto;
 grid-gap: 10px;
 width: 100%;
}

.findLegContainer > div {
 text-align: left;
}

img.headshot {
 width: 100%;
 height: auto;
 margin-bottom: 10px;
}
</style>
<div id="viewDiv"></div>

findmyleg.js


require([
 "esri/Map",
 "esri/views/MapView",
 "esri/layers/FeatureLayer",
 "esri/widgets/Legend",
 "esri/tasks/Locator",
 "esri/widgets/Search",
 "esri/tasks/QueryTask",
 "esri/tasks/support/Query",
 "dojo/domReady!"
 ], function(
 Map, MapView, FeatureLayer, Legend, Locator, Search, QueryTask, Query
 ) {
 
 //REST endpoints
 var senateServiceUrl = "Your REST endpoint for your senate data";
 var houseServiceUrl = "Your REST endpoint for your house data";
 var locatorServiceUrl = "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer";
 
 //Layer fill and lines
 var houseFill = {
 type: "simple-fill", // autocasts as new SimpleFillSymbol()
 style: "none",
 outline: { // autocasts as new SimpleLineSymbol()
 color: [165, 223, 65, 1],
 width: 1
 }
 };
 
 var senateFill = {
 type: "simple-fill", // autocasts as new SimpleFillSymbol()
 style: "none",
 outline: { // autocasts as new SimpleLineSymbol()
 color: [33, 151, 212, 1],
 width: 1
 }
 };
 
 //Renderers
 var houseRenderer = {
 type: "simple", // autocasts as new SimpleRenderer()
 symbol: houseFill
 };
 
 var senateRenderer = {
 type: "simple", // autocasts as new SimpleRenderer()
 symbol: senateFill
 };
 
 
 // Create the PopupTemplates
 var senatePopupTemplate = { // autocasts as new PopupTemplate()
 title: "Senator {FIRST_NAME} {LAST_NAME}",
 content: "<div class='findLegContainer'><div><img class='headshot' src='/sites/default/files/{MEMBER_PICTURE}' /></div>" +
 "<div><b>{CHAMBER}enate District {DISTRICT} </b><br />" +
 "E-mail: <a href='mailto: {EMAIL}'>{EMAIL}</a><br />" +
 "Webpage: <a href='https://community.esri.com/node/{WEBSITE}' target='_blank'>{FIRST_NAME} {LAST_NAME}</a></div></div>"
 };
 
 var housePopupTemplate = { // autocasts as new PopupTemplate()
 title: "Representative {FIRST_NAME} {LAST_NAME}",
 content: "<div class='findLegContainer'><div><img class='headshot' src='/sites/default/files/{MEMBER_PICTURE}' /></div>" +
 "<div><b>{CHAMBER}ouse District {DISTRICT} </b><br />" +
 "E-mail: <a href='mailto: {EMAIL}'>{EMAIL}</a><br />" +
 "Webpage: <a href='https://community.esri.com/node/{WEBSITE}' target='_blank'>{FIRST_NAME} {LAST_NAME}</a></div></div>" 
 };
 
 //Create Feature Layers
 var houseLyr = new FeatureLayer({
 url: houseServiceUrl,
 renderer: houseRenderer,
 popupTemplate: housePopupTemplate,
 legendEnabled: true,
 outFields: ["*"]
 });
 
 var senateLyr = new FeatureLayer({
 url: senateServiceUrl,
 renderer: senateRenderer,
 popupTemplate: senatePopupTemplate,
 outFields: ["*"]
 });
 
 //Instantiate map
 var map = new Map({
 basemap: "streets",
 layers: [houseLyr, senateLyr]
 });
 
 //Instantiate map view
 var view = new MapView({
 container: "viewDiv",
 map: map,
 center: [-105.358887, 39.113014],
 zoom: 7,
 popup: {
 //features: legPopups,
 dockEnabled: false,
 dockOptions: {
 buttonEnabled: false,
 breakpoint: false
 }
 }
 });

//Search widget
 var searchWidget = new Search({ 
 view: view,
 AllPlaceholder: "Rep or Senator Last Name",
 sources: [{
 locator: new Locator({ url: locatorServiceUrl }),
 singleLineFieldName: "SingleLine",
 name: "Place",
 localSearchOptions: {
 minScale: 300000,
 distance: 50000
 },
 placeholder: "Search Geocoder",
 maxResults: 3,
 maxSuggestions: 6,
 suggestionsEnabled: true,
 minSuggestCharacters: 0
 },
 {
 featureLayer: houseLyr,
 searchFields: ["LAST_NAME"],
 displayField: "LAST_NAME",
 exactMatch: false,
 outFields: ["*"],
 name: "House Members",
 maxResults: 10,
 maxSuggestions: 10,
 suggestionsEnabled: true,
 minSuggestCharacters: 0,
 placeholder: "example: Duran"
 },
 {
 featureLayer: senateLyr,
 searchFields: ["LAST_NAME"],
 displayField: "LAST_NAME",
 exactMatch: false,
 outFields: ["*"],
 name: "Senate Members",
 placeholder: "example: Sonnenberg",
 maxResults: 6,
 maxSuggestions: 6,
 suggestionsEnabled: true,
 minSuggestCharacters: 0
 }]
 
 });
 
 
 /*var legend = new Legend({
 view: view,
 layerInfos: [{
 layer: houseLyr,
 title: "House Boundary Color"
 },{
 layer: senateLyr,
 title: "Senate Boundary Color"
 }
 ]
 });

view.ui.add(legend, "bottom-right");*/
 
 
 //Add the search widget
 view.ui.add(searchWidget, {
 position: "top-left",
 index: 0
 });
 
 //Move zoom button to top right
 view.ui.move("zoom", "top-right");

});

find_my_leg.module

<?php

/*
 * @author Steve Peralta
 */

/*
 * Implements hook_menu().
 */
function find_my_leg_menu() {
 $items['findmylegislator'] = array(
 'title' => 'Find My Legislator',
 'page callback' => 'find_my_leg_page',
 'access callback' => TRUE,
 'type' => MENU_CALLBACK
 );
 
 
 return $items;
}

/**
 * Implements hook_theme()
 */
function find_my_leg_theme() {
 return array(
 'themekit' => array(
 'render element' => 'elements',
 'template' => 'theme/templates/find_my_leg_page',
 ),
 );
}

/**
 * Page callback for /findmylegislator.
 */
function find_my_leg_page() {
 return theme('themekit');
}

And that is it! I'm super new to Esri so there are some things to improve on here, I'm sure, but hope you get some use out of it.

View solution in original post

1 Reply
StevePeralta
New Contributor II

Okay, I will answer my own question after a few days of toiling over this. Drupal 7 is not friendly to the DOM and blasts it from left and right with all kinds of stuff, so the key is to get the Esri scripts and your custom scripts loaded at the same time which, for Drupal, means in the same file. There are other ways of doing this, but not without a lot of Drupal headaches. So!

1. Create your Drupal module. I created a module called "find_my_leg" which is short for "Find My Legislator." Directory/file structure looks like this:

  • modules/custom/find_my_leg
  • modules/custom/find_my_leg/find_my_leg.info
  • modules/custom/find_my_leg/find_my_leg.module
  • modules/custom/find_my_leg/theme
  • modules/custom/find_my_leg/theme/theme.inc
  • modules/custom/find_my_leg/theme/js/findmyleg.js
  • modules/custom/find_my_leg/theme/templates
  • modules/custom/find_my_leg/theme/templates/find_my_leg_page.tpl.php

    2. Write your map code. The only three files I'll provide code for here are "find_my_leg_page.tpl.php", "findmyleg.js," and "find_my_leg.module." The others are out of the scope of this post. Check Drupal 7 docs for more info.

-------------------------------

find_my_leg_page.tpl.php

<link rel="stylesheet" href="https://js.arcgis.com/4.6/esri/css/main.css">
<script defer src="https://js.arcgis.com/4.6/"></script>
<script defer src="/sites/all/modules/custom/find_my_leg/theme/js/findmyleg.js"></script>
<!-- Replace these with your own styles -->
<style>

main#main-content.main-content{
width: 100%;
margin-top: -50px;
}

#viewDiv {
 border: 1px solid #ccc;
 padding: 0px;
 margin: 0;
 height: 600px;
 width: 100%;
}

.findLegContainer {
 display: grid;
 grid-template-columns: 60px auto;
 grid-gap: 10px;
 width: 100%;
}

.findLegContainer > div {
 text-align: left;
}

img.headshot {
 width: 100%;
 height: auto;
 margin-bottom: 10px;
}
</style>
<div id="viewDiv"></div>

findmyleg.js


require([
 "esri/Map",
 "esri/views/MapView",
 "esri/layers/FeatureLayer",
 "esri/widgets/Legend",
 "esri/tasks/Locator",
 "esri/widgets/Search",
 "esri/tasks/QueryTask",
 "esri/tasks/support/Query",
 "dojo/domReady!"
 ], function(
 Map, MapView, FeatureLayer, Legend, Locator, Search, QueryTask, Query
 ) {
 
 //REST endpoints
 var senateServiceUrl = "Your REST endpoint for your senate data";
 var houseServiceUrl = "Your REST endpoint for your house data";
 var locatorServiceUrl = "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer";
 
 //Layer fill and lines
 var houseFill = {
 type: "simple-fill", // autocasts as new SimpleFillSymbol()
 style: "none",
 outline: { // autocasts as new SimpleLineSymbol()
 color: [165, 223, 65, 1],
 width: 1
 }
 };
 
 var senateFill = {
 type: "simple-fill", // autocasts as new SimpleFillSymbol()
 style: "none",
 outline: { // autocasts as new SimpleLineSymbol()
 color: [33, 151, 212, 1],
 width: 1
 }
 };
 
 //Renderers
 var houseRenderer = {
 type: "simple", // autocasts as new SimpleRenderer()
 symbol: houseFill
 };
 
 var senateRenderer = {
 type: "simple", // autocasts as new SimpleRenderer()
 symbol: senateFill
 };
 
 
 // Create the PopupTemplates
 var senatePopupTemplate = { // autocasts as new PopupTemplate()
 title: "Senator {FIRST_NAME} {LAST_NAME}",
 content: "<div class='findLegContainer'><div><img class='headshot' src='/sites/default/files/{MEMBER_PICTURE}' /></div>" +
 "<div><b>{CHAMBER}enate District {DISTRICT} </b><br />" +
 "E-mail: <a href='mailto: {EMAIL}'>{EMAIL}</a><br />" +
 "Webpage: <a href='https://community.esri.com/node/{WEBSITE}' target='_blank'>{FIRST_NAME} {LAST_NAME}</a></div></div>"
 };
 
 var housePopupTemplate = { // autocasts as new PopupTemplate()
 title: "Representative {FIRST_NAME} {LAST_NAME}",
 content: "<div class='findLegContainer'><div><img class='headshot' src='/sites/default/files/{MEMBER_PICTURE}' /></div>" +
 "<div><b>{CHAMBER}ouse District {DISTRICT} </b><br />" +
 "E-mail: <a href='mailto: {EMAIL}'>{EMAIL}</a><br />" +
 "Webpage: <a href='https://community.esri.com/node/{WEBSITE}' target='_blank'>{FIRST_NAME} {LAST_NAME}</a></div></div>" 
 };
 
 //Create Feature Layers
 var houseLyr = new FeatureLayer({
 url: houseServiceUrl,
 renderer: houseRenderer,
 popupTemplate: housePopupTemplate,
 legendEnabled: true,
 outFields: ["*"]
 });
 
 var senateLyr = new FeatureLayer({
 url: senateServiceUrl,
 renderer: senateRenderer,
 popupTemplate: senatePopupTemplate,
 outFields: ["*"]
 });
 
 //Instantiate map
 var map = new Map({
 basemap: "streets",
 layers: [houseLyr, senateLyr]
 });
 
 //Instantiate map view
 var view = new MapView({
 container: "viewDiv",
 map: map,
 center: [-105.358887, 39.113014],
 zoom: 7,
 popup: {
 //features: legPopups,
 dockEnabled: false,
 dockOptions: {
 buttonEnabled: false,
 breakpoint: false
 }
 }
 });

//Search widget
 var searchWidget = new Search({ 
 view: view,
 AllPlaceholder: "Rep or Senator Last Name",
 sources: [{
 locator: new Locator({ url: locatorServiceUrl }),
 singleLineFieldName: "SingleLine",
 name: "Place",
 localSearchOptions: {
 minScale: 300000,
 distance: 50000
 },
 placeholder: "Search Geocoder",
 maxResults: 3,
 maxSuggestions: 6,
 suggestionsEnabled: true,
 minSuggestCharacters: 0
 },
 {
 featureLayer: houseLyr,
 searchFields: ["LAST_NAME"],
 displayField: "LAST_NAME",
 exactMatch: false,
 outFields: ["*"],
 name: "House Members",
 maxResults: 10,
 maxSuggestions: 10,
 suggestionsEnabled: true,
 minSuggestCharacters: 0,
 placeholder: "example: Duran"
 },
 {
 featureLayer: senateLyr,
 searchFields: ["LAST_NAME"],
 displayField: "LAST_NAME",
 exactMatch: false,
 outFields: ["*"],
 name: "Senate Members",
 placeholder: "example: Sonnenberg",
 maxResults: 6,
 maxSuggestions: 6,
 suggestionsEnabled: true,
 minSuggestCharacters: 0
 }]
 
 });
 
 
 /*var legend = new Legend({
 view: view,
 layerInfos: [{
 layer: houseLyr,
 title: "House Boundary Color"
 },{
 layer: senateLyr,
 title: "Senate Boundary Color"
 }
 ]
 });

view.ui.add(legend, "bottom-right");*/
 
 
 //Add the search widget
 view.ui.add(searchWidget, {
 position: "top-left",
 index: 0
 });
 
 //Move zoom button to top right
 view.ui.move("zoom", "top-right");

});

find_my_leg.module

<?php

/*
 * @author Steve Peralta
 */

/*
 * Implements hook_menu().
 */
function find_my_leg_menu() {
 $items['findmylegislator'] = array(
 'title' => 'Find My Legislator',
 'page callback' => 'find_my_leg_page',
 'access callback' => TRUE,
 'type' => MENU_CALLBACK
 );
 
 
 return $items;
}

/**
 * Implements hook_theme()
 */
function find_my_leg_theme() {
 return array(
 'themekit' => array(
 'render element' => 'elements',
 'template' => 'theme/templates/find_my_leg_page',
 ),
 );
}

/**
 * Page callback for /findmylegislator.
 */
function find_my_leg_page() {
 return theme('themekit');
}

And that is it! I'm super new to Esri so there are some things to improve on here, I'm sure, but hope you get some use out of it.