Let's say I want to create a custom UI component / widget to add some functionality to a web app (build with the ArcGIS Maps SDK for JavaScript). And let's say I want to implement this as a standard Web Component (https://developer.mozilla.org/en-US/docs/Web/API/Web_components).Then I create a JavaScript module and I write a class that extends HTMLElement. In that class I can build the UI of the component. That works without problems.But in my custom component I also want to access the classes of the Maps SDK like the MapView and the Map. Maybe I want to create a GraphicsLayer and some Graphics in the component and add the layer to the map.This leeds to some questions:- What is the best way to import the classes of the Maps SDK in my module? Using the import statement or using the AMD style with require?- What is the best way to get a reference to the mapView or map object defined in the main HTML / JavaScript file of the web app in my new JavaScript module? The new module is separate from the main JS file and so I don't have direct access to objects defined in this main JS file. Somehow I have to get the reference over to the module file. How can that be done?Is there a sample showing how to do this?
Ok, let's look at a simple example. I created a minimalistic app with a HTML file (index.html) and a JavaScript file (main.js).And I created a simple web component that just adds a Graphic and a GraphicsLayer to the map and zooms to that location (MapComponent.js).
index.html
<html> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" /> <title>Simple mapping app</title> <style> html, body, #viewDiv { padding: 0; margin: 0; height: 100%; width: 100%; } </style> <link rel="stylesheet" href="https://js.arcgis.com/4.29/esri/themes/light/main.css"> <script type="module" src="./main.js"></script> </head> <body> <div id="viewDiv"></div> </body> </html>
main.js
import MapView from 'https://js.arcgis.com/4.29/@arcgis/core/views/MapView.js'; import Map from 'https://js.arcgis.com/4.29/@arcgis/core/Map.js'; import MapComponent from "./MapComponent.js"; const map = new Map({ basemap: "osm" }); const view = new MapView({ map: map, center: [-118.805, 34.027], zoom: 13, container: "viewDiv" }); const mapComponent = document.createElement("map-component"); mapComponent.setView(view); view.ui.add(mapComponent, "top-right");
MapComponent.js
import MapView from 'https://js.arcgis.com/4.29/@arcgis/core/views/MapView.js'; import Map from 'https://js.arcgis.com/4.29/@arcgis/core/Map.js'; import GraphicsLayer from 'https://js.arcgis.com/4.29/@arcgis/core/layers/GraphicsLayer.js'; import Graphic from 'https://js.arcgis.com/4.29/@arcgis/core/Graphic.js'; export default class MapComponent extends HTMLElement{ constructor(){ super(); this.shadow = this.attachShadow({ mode: 'open' }); } setView(view){ this.view = view; } connectedCallback() { let goToButton = document.createElement("div"); goToButton.setAttribute("style", "background-color:#d9dde0;padding:2px 6px;cursor:pointer"); goToButton.textContent = "Add Graphic"; this.shadow.appendChild(goToButton); goToButton.addEventListener("click", (function(){ this.addGraphic(); }).bind(this)); } addGraphic(){ let point = { type: "point", longitude: -71.2643, latitude: 42.0909 }; let markerSymbol = { type: "simple-marker", color: [226, 119, 40] }; let graphic = new Graphic({ geometry: point, symbol: markerSymbol }); let graphicsLayer = new GraphicsLayer(); graphicsLayer.add(graphic); this.view.map.add(graphicsLayer); this.view.goTo(graphic); } } customElements.define("map-component", MapComponent);
In the app (main.js) the mapView and map are created. The component is imported, added and the reference to the mapView of the application is passed to it with the setView method of the component. Is there perhaps a better way to pass the reference to the mapView to the web component? In the module of the component the classes of the maps SDK are imported from the CDN and not locally, because I don't know whether an existing web application that wants to use the component uses a local version of the maps SDK.Is there anything fundamental that should be changed or improved in this example?
It would be the same thing minus the application part. You can expose the view or map on your components for users. You could even build a thin API of methods on your components to handle custom tasks, like zoom to graphics or turn layers on/off. You would probably want to use a build tool like Vite to bundle your components. With Vite you can set the maps sdk as an external dependency. I forget if it's directly in Vite config or as part of the rollup plugin part. But you don't want the maps sdk in your bundles, let the app do that.
There is also an option to use any of the web component compilers/frameworks out there like Stencil or Lit, even Svelte can compile to WC.
Thanks for your example. It seems that it is a complete web app and the different components are not independent in this sample.What I want to do is create a separate widget as a Web Component that is completely independent from the rest of the application. So someone else can just take this component and put it in his own web app.In the easiest case you could just take one of the simple Esri examples from the Maps SDK documentation and put it in an HTML file. Then it should be possible to add the custom web component to this sample app just as you would add a legend widget. So the sample app has already a mapView object defined and it should be possible to access this mapView object insite of the new web component ( e. g. to call mapView.goTo(...)If the web component is completely independant and is also used by others I think it is not a good idea to rely on special build system, Vite or something else. Some people don't use that but just write simple HTML and JavaScript files.
I'm not shure what you meen with the last part (treat the SDK modules as external modules).
Here is a version of an app I have done before in various frameworks, but this one uses vanilla web components.
https://github.com/odoe/nearby-app-vanilla
If you plan on building your components as your own package that you can use across various apps, do not build the JS SDK modules into your components. You want to treat them as external modules. You can do this by looking at the documentation for your build tools.
Les membres connectés peuvent publier, suivre les mises à jour, et plus encore. Nouveau ici ? Inscrivez-vous gratuitement.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.