Skip to content
This repository was archived by the owner on Nov 6, 2024. It is now read-only.

Commit df948f5

Browse files
committed
update CHANGELOG and Using Classes Synchonously section of README
1 parent abaadf0 commit df948f5

File tree

2 files changed

+49
-71
lines changed

2 files changed

+49
-71
lines changed

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,17 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55
## [Unreleased]
66
### Added
77
### Changed
8+
- added "Using Modules Synchronously" to the docs (README) - thanks [@stdavis](https://github.com/stdavis)!
89
### Fixed
10+
- `css: true` uses the correct URL the light theme (`/esri/themes/light/main.css`) - thanks [@stdavis](https://github.com/stdavis)
911
### Removed
1012
### Breaking
1113

1214
## [2.10.1] - 2019-09-27
1315

16+
### Changed
17+
- Added generics for `loadModules` typings improvements. #183 - thanks [@deskoh](https://github.com/deskoh)!
18+
1419
## [2.10.0] - 2019-07-03
1520
### Added
1621
- default to JSAPI 4.12; update docs w/ latest version numbers

Diff for: README.md

+44-71
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ See the [Examples](#examples) section below for links to applications that use t
2929
- [Why is this needed?](#why-is-this-needed)
3030
- [Examples](#examples)
3131
- [Advanced Usage](#advanced-usage)
32-
- [Using Classes Synchronously](#using-classes-synchronously)
3332
- [ArcGIS Types](#arcgis-types)
33+
- [Using Classes Synchronously](#using-classes-synchronously)
3434
- [Configuring Dojo](#configuring-dojo)
3535
- [Overriding ArcGIS Styles](#overriding-arcgis-styles)
3636
- [Pre-loading the ArcGIS API for JavaScript](#pre-loading-the-arcgis-api-for-javascript)
@@ -289,76 +289,6 @@ See the [examples over at ember-esri-loader](https://github.com/Esri/ember-esri-
289289

290290
### [FAQS](https://github.com/Esri/esri-loader/issues?utf8=%E2%9C%93&q=label%3AFAQ+sort%3Aupdated-desc)
291291

292-
### Using Classes Synchronously
293-
294-
Let's say you need to create a map in one component, and then in another component create a legend. In this scenario, you need to create the map first, then create the legend only once you have a reference to the map. However, it is unlikely that you have both references to both DOM nodes at the time you want to start creating the map (for example if the legend component is a child of the map component and it's render lifecycle hasn't started yet).
295-
296-
One way to do this would be to add functions like this to a service (or any singleton module in your app):
297-
298-
```javascript
299-
newMap (elem, options) {
300-
// load BOTH the map AND legend modules
301-
// even though we're not using the Legend at this time
302-
return loadModules(['esri/map', 'esri/dijit/Legend']).then(([Map, Legend]) => {
303-
if (!this._Legend) {
304-
// keep a reference to the Legend class so that legends can now be created synchronously
305-
this._Legend = Legend;
306-
}
307-
// create and return the map
308-
return new Map(elem, options);
309-
}
310-
);
311-
}
312-
// synchronous function to create a new legend
313-
// will throw an error if newMap() has not already been called and returned
314-
newLegend (params, srcNodeRef) {
315-
if (this._Legend) {
316-
return this._Legend(params, srcNodeRef);
317-
} else {
318-
throw new Error('You must have loaded a map before creating a legend.');
319-
}
320-
}
321-
```
322-
323-
Once the map component's DOM has loaded (like `ngInit()` or `componentDidMount()`) you can run something like:
324-
325-
```javascript
326-
mapService.newMap(elemRef, options).then(map => {
327-
// TODO: somehow signal to the legend component that the map has loaded
328-
// i.e. pass it down as a prop, etc
329-
});
330-
```
331-
332-
In the legend component, whenever you receive a new map instance (i.e. via prop, etc), you can run something like:
333-
334-
```javascript
335-
this.legend = mapService.newLegend({ map: this.map }, elemRef);
336-
this.legend.startup();
337-
```
338-
339-
While that is a little complicated, an advantage of this pattern is that you are in complete control over which modules can be made available synchronously, so there's no mystery about why attempts to load modules synchronously might fail (either because the JSAPI hasn't been loaded, or the module is not one of the ones that can be loaded synchronously).
340-
341-
This encourages you to:
342-
343-
1. consolidate your use of ArcGIS API modules in a single or few locations
344-
1. use only the ArcGIS API modules you need to do ArcGIS API things (map or 3D scene visualizations) and rely on your framework of choice, arcgis-rest-js, and/or modern JavaScript/TypeScript for everything else
345-
346-
The key to success with this kind of pattern is to not overgeneralize, i.e. "adding every module to the modules list and creating a property on the service for each module (for typings and ease of calling)." Instead, focus on the specific workflows of your application. For example, let's say your app has a sidebar component that will need to at some point create a new `SimpleMarkerSymbol`, and you know that component is only visible once the map component has loaded. For this scenario, your service's `createMap()` can lazy-load `SimpleMarkerSymbol` along with whatever other modules it needs to show the map and then set `this._SimpleMarkerSymbol` so that the service's `addSymbolToMap(symbolJson)` will be available the sidebar component:
347-
348-
```javascript
349-
addSymbolToMap(symbolJson) {
350-
if (this._SimpleMarkerSymbol) {
351-
const symbol = new this._SimpleMarkerSymbol(symbolJson)
352-
// TODO: add the symbol to this._map, etc
353-
} else {
354-
// this should never happen, but just in case
355-
throw new Error('map not loaded yet')
356-
}
357-
}
358-
```
359-
360-
Sure, it would be a pain to create such a wrapping function for every module, but if you focus on your app's specific workflows, we bet you'll find that you should only need it for a few modules/classes.
361-
362292
### ArcGIS Types
363293

364294
This library doesn't make any assumptions about which version of the ArcGIS API you are using, so you will have to install the appropriate types. Furthermore, because you don't `import` esri modules directly with esri-loader, you'll have to follow the instructions below to use the types in your application.
@@ -408,6 +338,49 @@ A more complete 3.x sample can be [seen here](https://codesandbox.io/s/rj6jloy4n
408338
409339
For Angular CLI applications, you will also need to add "arcgis-js-api" to `compilerOptions.types` in src/tsconfig.app.json and src/tsconfig.spec.json [as shown here](https://gist.github.com/tomwayson/e6260adfd56c2529313936528b8adacd#adding-the-arcgis-api-for-javascript-types).
410340
341+
### Using Classes Synchronously
342+
343+
Let's say you need to create a map in one component, and then later in another component add a graphic to that map. Unlike creating a map, creating a graphic and adding it to a map is ordinarily a synchronous operation, so it can be inconvenient to have to wait for `loadModules()` just to load the `Graphic` class. One way to handle this is have the function that creates the map _also_ load the `Graphic` class before its needed. You can then hold onto that class for later use to be exposed by a function like `addGraphicToMap(view, graphicJson)`:
344+
345+
```javascript
346+
// utils/map.js
347+
import { loadModules } from 'esri-loader';
348+
349+
// NOTE: module, not global scope
350+
let _Graphic;
351+
352+
// this will be called by the map component
353+
export function loadMap(element, mapOptions) {
354+
// NOTE:
355+
return loadModules(['esri/Map', 'esri/views/MapView', 'esri/Graphic'], {
356+
css: true
357+
}).then(([Map, MapView, Graphic]) => {
358+
// hold onto the graphic class for later use
359+
_Graphic = Graphic;
360+
// create the Map
361+
const map = new Map(mapOptions);
362+
// return a view showing the map at the element
363+
return new MapView({
364+
map,
365+
container: element
366+
});
367+
});
368+
}
369+
370+
// this will be called by the component that needs to add the graphic to the map
371+
export function addGraphicToMap(view, graphicJson) {
372+
// make sure that the graphic class has already been loaded
373+
if (!_Graphic) {
374+
throw new Error('You must load a map before creating new graphics');
375+
}
376+
view.graphics.add(new _Graphic(graphicJson));
377+
}
378+
```
379+
380+
You can [see this pattern in use in a real-world application](https://github.com/tomwayson/create-arcgis-app/blob/master/src/utils/map.js).
381+
382+
See [#124 (comment)](https://github.com/Esri/esri-loader/issues/124#issuecomment-408482410) and [#71 (comment)](https://github.com/Esri/esri-loader/issues/71#issuecomment-381356848) for more background on this pattern.
383+
411384
### Configuring Dojo
412385
413386
You can pass a [`dojoConfig`](https://dojotoolkit.org/documentation/tutorials/1.10/dojo_config/) option to `loadModules()` or `loadScript()` to configure Dojo before the script tag is loaded. This is useful if you want to use esri-loader to load Dojo packages that are not included in the ArcGIS API for JavaScript such as [FlareClusterLayer](https://github.com/nickcam/FlareClusterLayer).

0 commit comments

Comments
 (0)