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.
Solved! Go to Solution.
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:
-------------------------------
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.
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:
-------------------------------
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.