You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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>

关键修改点

  1. 将原始PopupTemplate命名为basePopTemplate,作为克隆的原型;
  2. 在监听弹窗选中要素时,使用basePopTemplate.clone()创建独立的模板副本;
  3. 修改副本的字段可见性,而非直接修改共享模板;
  4. 将修改后的副本赋值给view.popup.popupTemplate,确保当前弹窗使用独立的模板实例。

内容的提问来源于stack exchange,提问作者Robert Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 14:16:02