Esri/esri-loader

esri loader Angular example

banchana opened this issue · 18 comments

Has anyone worked with esri-loader and have implemented successfully?

I am looking at the cli example (https://github.com/tomwayson/esri-angular-cli-example) listed on the esri-loader site (https://github.com/Esri/esri-loader) and it is still using the old libraries.

Is there a lot of difference in terms of how it is implemented in various files shown here in this link https://gist.github.com/tomwayson/e6260adfd56c2529313936528b8adacd?

Thanks!

@banchana

Here is a recent commit that migrates an angular repo from using angular-esri-loader to esri-loader:

jccartwright/autogrid@3b4fcaf

@banchana here's a component that may help you out. It was last tested with esri-loader v1.5 + angular/cli: 1.5.0 + angular 5.0.1 . I'm looking at creating an updated repo, it's a work in progress.


import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

import { loadModules } from 'esri-loader';

@Component({
  selector: 'app-esri-map',
  templateUrl: './esri-map.component.html',
  styleUrls: ['./esri-map.component.css']
})


export class EsriMapComponent implements OnInit {

  // for JSAPI 4.x you can use the "any for TS types
  public mapView: any;
  // public dojoConfig: any;

  // this is needed to be able to create the MapView at the DOM element in this component
  @ViewChild('mapViewNode') private mapViewEl: ElementRef;

  constructor() { }

  public ngOnInit() {

    return loadModules([
      'esri/Map',
      'esri/views/MapView'
    ]).then(([Map, MapView]) => {
      const mapProperties: any = {
        basemap: 'hybrid'
      };

      const map: any = new Map(mapProperties);

      const mapViewProperties: any = {
        // create the map view at the DOM element in this component
        container: this.mapViewEl.nativeElement,
        // supply additional options
        center: [-12.287, -37.114],
        zoom: 12,
        map // property shorthand for object literal
      };

      this.mapView = new MapView(mapViewProperties);
    })
      .catch(err => {
        console.log(err);
      });
  } 
}


Thank you Tom and Andy for your prompt response to my issue. I will work towards implementing this and will provide my feedback to you once I am done. Appreciate your efforts.

So @andygup

I see you're using any types in there. Are these instructions no longer valid?

https://github.com/Esri/esri-loader#4x-types

Hey esri-loader team,
i have implemented the new stuff successfully.
I know your repo is still in progress, but I just wanted to let you know about one file that is still referencing the old angular-esri-loader, that was in esri-map.component.ts file. I updated that with what I thought should look like and was able to get my map working.
Thanks Much!
Banchana

@tomwayson good catch, yes the best practice is to continue to use the __esri.XYZ pattern. For reference, in case others aren't sure what this means, you can grab the ArcGIS JS API type definitions via: https://github.com/Esri/jsapi-resources/tree/master/4.x/typescript

@banchana I'm going to close this issue since you seem to have it working, feel free to reopen if needed.

Are there more advanced operations for both the angular and arcgis apis?Such as spatial query, and attribute query.I want to turn the arcgis API into a service, and then import the service in other components to get the classes in the service, such as app.map = map;App. Color = Color.I'm in other components, I just need to get this app, and I can, without using the loadModules function over and over again.

@Huwei1158 please see the 2018 Esri Dev Summit presentation slides that discuss some of the topics you're asking about: https://github.com/Esri/jsapi-resources/tree/master/frameworks/angular#presentations

@Huwei1158 esri-loader definitely complicates interaction w/ the ArcGIS API for JavaScript in that you do need to wrap any functions that use 'esri' modules in a call to loadModules(). This means that something that might have previously been synchronous like creating a new Extent() from JSON now becomes asynchronous b/c it has to be wrapped in a promise. For this reason, esri-loader works best when your app makes limited use of the ArcGIS API. You are following best practices by isolating all interaction w/ the ArcGIS API into a service, but I don't know of a better approach than for that service to expose async functions like newMap(elementId, options), newColor(colorJSON), etc.

@jwasilgeo Thank you. My level is limited, we are using arcgis api@3.18, and I want to turn it into the following:

import { Injectable } from '@angular/core';
import { loadScript, loadModules } from 'esri-loader'
@Injectable()
export class EsriService {
	map:any;
	config:any;
  constructor() { 
	var options = {
			url: 'http://218.241.213.230:8888/arcgis_js_api/library/3.18/3.18/init.js',
		};
		loadScript(options);
		loadModules(['esri/map','esri/config'],options).then(([Map,Config])=>{
//			this.map = Map;				
//			this.config = Config;
				this.map = function(a,b){
				return a*b
				} 
		});
//		this.map = function(a,b){
//		return a*b
//		}
  }
  

}

How do you break this callback function, get the Map in like this.map, output it, and then use it in the component.

import { Injectable } from '@angular/core';
import { loadScript, loadModules } from 'esri-loader'

var options = {
  url: 'http://218.241.213.230:8888/arcgis_js_api/library/3.18/3.18/init.js',
};

@Injectable()
export class EsriService {

  esriConfig() {
		return loadModules(['esri/config'], options).then(([esriConfig]) => {
			return esriConfig;
		});
  },

  newMap(elementId, mapOptions) {
    return loadModules(['esri/map'], options).then(([Map]) => {
      return new Map(elementId, mapOptions);
    });
	}
}

Then in your component you might do something like:

mapService.esriConfig().then(esriConfig => {
	// TODO: do something w/ esriConfig here as needed, such as:
	esriConfig.defaults.io.corsEnabledServers.push('myserver');
	mapService.newMap('mapDiv',  { displayGraphicsOnPan:false }).then(map => {
		// TODO: do something w/ your map instance, like:
		map.on('extent-change', (delta, nexExtent) => {
			console.log(newExtent);
		});
	});
});

Thank you. This is not what I want. Two returns are too much trouble.Every module has to be written.I used to combine with webpack and use promise to get the module directly.But I won't with angular.Here's what I did with webpack:
1.this is map.js

import esriLoader from 'esri-loader';
import arcgis_url from 'Conf/arcgisUrl';

var app = {};

/*

初始化地图,id为需要绑定的map id
*/
app.initMap = function(id){
var that = this;
var p = new Promise(function(resolve, reject){
esriLoader.loadModules(['dojo/parser', 'esri/config', 'esri/map', 'esri/layers/ArcGISDynamicMapServiceLayer','esri/layers/FeatureLayer',
"esri/toolbars/MeasureTools", "dojo/_base/array", "esri/layers/LayerDrawingOptions", "dojo/on", "dojo/query",
"esri/tasks/query", "esri/tasks/QueryTask", "esri/layers/GraphicsLayer", "esri/tasks/FindTask","esri/tasks/FindParameters", 'esri/tasks/BufferParameters', 'esri/SpatialReference', "esri/geometry/Extent",
'esri/toolbars/navigation', 'esri/toolbars/draw', 'esri/tasks/GeometryService', 'esri/symbols/Font',
'esri/symbols/SimpleMarkerSymbol', 'esri/symbols/SimpleFillSymbol', 'esri/symbols/SimpleLineSymbol',
'esri/symbols/TextSymbol', 'esri/Color', 'esri/graphic', 'esri/tasks/LengthsParameters', 'esri/geometry/Point',
'esri/geometry/Polyline', 'esri/tasks/AreasAndLengthsParameters', 'dojo/dom-attr', 'esri/geometry/normalizeUtils', 'dojo/domReady!'], arcgis_url.initUrl)
.then(([parser, esriConfig, Map, ArcGISDynamicMapServiceLayer, FeatureLayer, deMeasureTools, arrayUtils, LayerDrawingOptions, on, query,
Query, QueryTask, GraphicsLayer,FindTask,FindParameters,BufferParameters, SpatialReference, Extent,
Navigation, Draw, GeometryService, Font, SimpleMarkerSymbol, SimpleFillSymbol, SimpleLineSymbol,
TextSymbol, Color, Graphic, LengthsParameters, Point, Polyline, AreasAndLengthsParameters, domAttr, normalizeUtils]) => {
console.log(arcgis_url);

parser.parse();
esriConfig.defaults.io.corsEnabledServers.push("218.241.213.230:6080");
esriConfig.defaults.io.corsEnabledServers.push("sampleserver1.arcgisonline.com");
esriConfig.defaults.geometryService = new GeometryService(arcgis_url.GeometryService);
 esriConfig.defaults.io.proxyUrl = "http://218.241.213.230:8888/Java/proxy.jsp";
	esriConfig.defaults.io.alwaysUseProxy = false;
// create map with the given options at a DOM node w/ id 'mapNode'
/*extent:new Extent(121,29,122,29.5, new SpatialReference({ wkid:4610 }))*/
that.map = new Map(id, {
	  	center: [121.4, 29.3],
 	zoom: 11,
 	logo:false,
});

//设置地图坐标系类型  
 var spatialReference = new SpatialReference(4610);  
 that.map.spatialReference = spatialReference;  
var basemap = new ArcGISDynamicMapServiceLayer(arcgis_url.basemap);
basemap.id = "basemap";
 that.map.addLayer(basemap);
 //自己封装的测量工具,在服务器arcgisapi中
 var measurTool = new deMeasureTools({
     map: that.map
 }, "map-tool");
 /*that.map.onClick = function(e){
 	var t = e;
 	console.log(e);
 };*/
 
 var fieldsSelectionSymbol =new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
 new SimpleLineSymbol(SimpleLineSymbol.STYLE_DASHDOT,
new Color([255, 0, 0]), 2), new Color([255, 255, 0, 0.5]));
that.Map = Map;
that.ArcGISDynamicMapServiceLayer=ArcGISDynamicMapServiceLayer;
that.FeatureLayer=FeatureLayer;
that.Navigation=Navigation;
that.arrayUtils = arrayUtils;
that.LayerDrawingOptions = LayerDrawingOptions;
that.SimpleFillSymbol=SimpleFillSymbol;
that.SimpleLineSymbol=SimpleLineSymbol;
that.Color=Color;
that.Query=Query;
that.Graphic=Graphic;
that.GraphicsLayer=GraphicsLayer;
that.esriConfig=esriConfig;
that.BufferParameters=BufferParameters;
that.SpatialReference=SpatialReference;
that.Extent=Extent;
that.GeometryService=GeometryService;
that.FindTask=FindTask;
that.FindParameters=FindParameters;
that.Point=Point;
that.SimpleMarkerSymbol=SimpleMarkerSymbol;
that.QueryTask=QueryTask;
that.query=query;
that.Draw=Draw;
that.normalizeUtils=normalizeUtils;
/*that.Draw=Draw;
that.Font=Font;
that.TextSymbol=TextSymbol;
that.LengthsParameters=LengthsParameters;
that.Polyline=Polyline;
that.AreasAndLengthsParameters=AreasAndLengthsParameters;
that.domAttr=domAttr;*/
resolve({
	ok:true
});
}).catch(err => {

console.error(err);
});
})
return p;
}
export default app;

2.this is other js:

import esris from './map';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap';
import arcgis_url from 'Conf/arcgisUrl';
var gpsMap = {};
gpsMap.mapRoad = function(roadName,serverUrl){
var map = esris.map;
//乡镇定位的函数
map.graphics.clear();//清空graphics
//实例化查询参数
var findParams = new esris.FindParameters();
findParams.returnGeometry = true;
findParams.layerIds = [2];//对地级城市和省记性查询
findParams.searchFields = ['GLMC'];//匹配图层中的字段属性
findParams.searchText = roadName;
var findTask = new esris.FindTask(serverUrl);
//进行查询
findTask.execute(findParams,showFindResult);
//查询结果匹配
function showFindResult(queryResult){
if (queryResult.length === 0) {
alert("查询无结果");
return;
}
console.log(queryResult)
$.each(queryResult, function(index, value) {
var pointSymbol = new esris.SimpleMarkerSymbol(//定义点符号
esris.SimpleMarkerSymbol.STYLE_CIRCLE, 10,
new esris.SimpleLineSymbol(esris.SimpleLineSymbol.STYLE_SOLID,
new esris.Color([255,0,0]), 1),
new esris.Color([255,0,0])
);
var outline= new esris.SimpleLineSymbol(esris.SimpleLineSymbol.STYLE_DASHDOT,new esris.Color([255, 0, 0]), 1); //定义面的边界线符号
var PolygonSymbol = new esris.SimpleFillSymbol(esris.SimpleFillSymbol.STYLE_SOLID, outline,new esris.Color([0, 255, 0, 1])); //定义面符号
var graphic ={}; //创建graphic
var locationPoint ={};//创建定位点
var geometry = value.feature.geometry;//获得该图形的形状
if(geometry.type == 'polygon'){
graphic = new esris.Graphic(geometry, PolygonSymbol);
locationPoint=geometry.getCentroid();
}
else if(geometry.type == 'point'){
graphic = new esris.Graphic(geometry, pointSymbol);
locationPoint=geometry;
}
//	map.graphics.add(graphic);
console.log(graphic)
console.log(locationPoint)
// map.centerAndZoom(locationPoint,1);
});
}
}

This is my ideal example.
But I don't know how to do it with a little bit of it?

@Huwei1158

Here's an example service that uses a promise esri-map.service.ts, and here's an example of the component that injects it esri-map.component.ts.

Note, the best practice is to defer loading of modules that aren't needed immediately, this is also referred to as lazy loading. Loading all the modules at the same time creates a performance bottleneck that can degrade the end user experience.

@Huwei1158

Other than what I've suggested above, the pattern I describe here in this is the only other suggestion I have for you. If either of those don't work, then perhaps esri-loader is not the right solution for you.

Does anyone know why my esri-loader is not able to load GraphicsLayerView ??

@MohamadMousheimish do you have a bin/fiddle/sandbox that demonstrates that?