使用ArcGIS JavaScript API 4.x的GraphicsLayer时,弹窗无法正确隐藏字段
ArcGIS JS API 4.x GraphicsLayer弹窗字段无法正确隐藏的解决方法
问题现象
使用ArcGIS JavaScript API 4.x的GraphicsLayer时,弹窗无法正确隐藏字段(该功能在FeatureLayer中可正常工作,但需求必须使用GraphicsLayer)。问题复现步骤:
- 先点击左侧三角形图形,弹窗可正常显示所有字段;
- 先点击右侧三角形图形(其
address属性为null),再点击左侧三角形图形,左侧图形的弹窗将不显示任何字段。
问题根源
所有Graphic对象共享了同一个PopupTemplate实例。当通过getEffectivePopupTemplate()获取模板并修改其fieldInfos的visible属性时,这些修改会直接作用于这个共享的模板对象上。后续其他Graphic使用该模板时,会继承之前的修改,最终导致弹窗显示异常。
解决方案
每次弹窗触发时,克隆原始PopupTemplate的副本,对副本进行字段可见性的修改,再将副本应用到当前弹窗。这样每个Graphic的弹窗都会使用独立的模板实例,不会互相干扰。
修改后的完整代码:
<html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" /> <title> Custom popup actions per feature attribute | JavaScript 4.27 </title> <style> body { padding: 0; margin: 0; height: 100%; width: 100%; overflow: hidden; } #viewDiv { position: absolute; right: 0; left: 0; top: 0; bottom: 0; } </style> <link rel="stylesheet" href="https://js.arcgis.com/4.27/esri/themes/light/main.css" /> <script src="https://js.arcgis.com/4.27/"></script> <script> require(["esri/Map", "esri/views/MapView", "esri/layers/GraphicsLayer", "esri/geometry/Polygon","esri/Graphic", "esri/PopupTemplate", "esri/core/reactiveUtils"], ( Map, MapView, GraphicsLayer, Polygon, Graphic, PopupTemplate, reactiveUtils ) => { const map = new Map({ basemap: "streets-navigation-vector" }); const view = new MapView({ container: "viewDiv", map: map, center: [-112.42914,38.771353], zoom: 5 }); /******************** * Add boundary polygon/symbol ********************/ const boundaryPolygon1 = new Polygon({ hasZ: false, hasM: false, rings: [[[-112.42914,38.771353],[-112.324772,38.891169],[-112.571965,38.899720]]] }); const boundaryPolygon2 = new Polygon({ hasZ: false, hasM: false, rings: [[[-111.52914,38.771353],[-111.424772,38.891169],[-111.671965,38.899720]]] }); const theSymbol = { type: "simple-fill", style: "solid", color: [200, 40, 40, 1], outline: { color: [255, 0, 0, 255], width: 2, type: "simple-line", style: "solid" } }; /******************** * Add graphics layer ********************/ let myAtt1 = { ObjectID: 1, name: "John Ross", address: "1234 Main Street" }; let myAtt2 = { ObjectID: 2, name: "Bob Cattle", address: null }; const graphicsLayer = new GraphicsLayer(); map.add(graphicsLayer); // 原始模板,作为克隆的原型 const basePopTemplate = new PopupTemplate({ title: "Graphic Test", content: [ { type: "fields", fieldInfos: [ { fieldName: "ObjectID" }, { fieldName: "name" }, { fieldName: "address" } ] } ] }); const boundaryGraphic1 = new Graphic({ geometry: boundaryPolygon1, symbol: theSymbol, attributes: myAtt1, popupEnabled: true, popupTemplate: basePopTemplate }); const boundaryGraphic2 = new Graphic({ geometry: boundaryPolygon2, symbol: theSymbol, attributes: myAtt2, popupEnabled: true, popupTemplate: basePopTemplate }); view.when(() => { graphicsLayer.add(boundaryGraphic1); graphicsLayer.add(boundaryGraphic2); }); view.when(() => { // 监听弹窗选中的要素 reactiveUtils.watch(() => view.popup.selectedFeature, (graphic) => { if (graphic) { // 克隆原始模板,创建独立实例 const popupTemplateClone = basePopTemplate.clone(); // 根据当前要素属性调整字段可见性 for(const fi of popupTemplateClone.content[0].fieldInfos) { const fieldValue = graphic.attributes[fi.fieldName]; fi.visible = !!fieldValue; } // 将修改后的模板应用到当前弹窗 view.popup.popupTemplate = popupTemplateClone; } }); }); }); </script> </head> <body class="light"> <div id="viewDiv" class="esri-widget"></div> </body> </html>
关键修改点
- 将原始PopupTemplate命名为
basePopTemplate,作为克隆的原型; - 在监听弹窗选中要素时,使用
basePopTemplate.clone()创建独立的模板副本; - 修改副本的字段可见性,而非直接修改共享模板;
- 将修改后的副本赋值给
view.popup.popupTemplate,确保当前弹窗使用独立的模板实例。
内容的提问来源于stack exchange,提问作者Robert Smith
相关产品推荐
相关产品推荐

