Display Info Window on the multiple coordinates on the arcgis map in Next JS

Here below is my next JS Code which is showing a simple ArcGIS map with the points or markers on the specific coordinates.

Can anyone please let me know that how can I display the popup / Info window for the points on the map? e.g. I click on any point and it will open a corresponding popup on it.

import NavBar from '@/components/NavBar'
import axios from 'axios';
import { useRef, useEffect, useState } from 'react';
import { loadModules } from 'esri-loader';

export default function Home({...props}) {
    const [state, setState] = useState('');
    const MapElement = useRef(null)
    const options = {
     url: 'https://js.arcgis.com/4.6/',
     css: true
    };

    useEffect(() => {
        var vehicleData = props.data
        var map, point_symbol;
        loadModules([
            "esri/views/MapView",
            "esri/WebMap",
            "esri/Graphic",          
            "esri/geometry/Point",
            "esri/PopupTemplate",
            "esri/layers/FeatureLayer","dojo/domReady!"
        ],options).then(([ MapView, WebMap, Graphic, Point, PopupTemplate, FeatureLayer]) => {
            const webmap = new WebMap({
                basemap: "gray-vector"
            })

            var map = new MapView({
                map: webmap,
                center:[-6.357768833333333,  53.415487166666665],
                zoom:6,
                container: MapElement.current
            })

            map.popup.autoOpenEnabled = false;
            
            for(var i=0, i_length=vehicleData.length; i<i_length; i++){
                point_symbol = new Point({
                    longitude:vehicleData[i].longitude,
                    latitude: vehicleData[i].latitude,
                    spatialReference: { wkid: 3857 }
                })   
                
                var template = new PopupTemplate({
                    title: vehicleData[i].company,
                    content: vehicleData[i].description
                });
    
                var graphic_symbol = new Graphic({
                    geometry: point_symbol,
                    symbol: {
                        type: "simple-marker",
                        style: "circle",
                        color: "orange",
                        size: "18px",
                        outline: {
                            color: [150, 200, 255],
                            width: 5
                        } 
                    },
                    popupTemplate: template
                });
                map.graphics.add(graphic_symbol)   
            }

            

            map.on("click", function(event) {
                map.popup.open({
                  location: event.mapPoint,
                  
                  features: [graphic_symbol]
                });
              });



            // map.on("click", function(event) {
            //     console.log(vehicleData)
            //     map.popup.open({
            //         location: event.mapPoint,  // location of the click on the view
            //         title: "You clicked here",  // title displayed in the popup
            //         content: "Your description here"  // content displayed in the popup
            //     });
            // });
        })

        return () => {  
            if(!!map) {
                map.destroy()
                map=null
            }
        }
    })

    return (
        
        <div id="home-container"> 
            
        <NavBar />

            <div className="app-wrapper" >
                <div className="app-content">
                    <div className="no-padding">
                        <div className="row gy-4">
                            <div className="col-12">
                                <div style={{height:1000, width:1400}} ref={MapElement}></div>
                            </div>
                        </div>
                    </div>
                </div>
            </div> 

        </div>
    )
}

export async function getServerSideProps(context) {

    let response = await axios(process.env.BASE_URL +'/devices/all',{
        headers : {
            'Authorization' : 'Bearer ' + process.env.TOKEN
        }
    })

    let data = await response.data
    return {
        props : {
            data: data
        }
    }
}

I need to display pop-up or info window corresponding to each markup multiple circles on the map. In the above code, API call is done by getServerSideProps, and data as an array of objects is passed to the component using props.

I am able to display multiple circles on the map but don't know how to display info window corresponding to each marker?

enter image description here


Solution 1:

I think that in your code you are having a context problem with the variable i. When the popup shows the value of i always gonna be vehicleData.length.

So you can solve the context problem using let instead of var, but I will suggest you another approach.

Declare template, the popup template, outside the loop, and use two new properties that we will add in the next step.

var template = new PopupTemplate({
    title: "{company}",
    content: "{description}"
    outFields: ["*"],
    fieldInfos: [
        { fieldName: "company" },
        { fieldName: "description" }
    ]
});

Add the information you want to display, to the attributes of the graphics, like this,

var graphic_symbol = new Graphic({
    geometry: point_symbol,
    symbol: {
        type: "simple-marker",
        style: "circle",
        color: "orange",
        size: "18px",
        outline: {
            color: [150, 200, 255],
            width: 5
        } 
    },
    popupTemplate: template,
    attributes: {  // <- here
        company: vehicleData[i].company,
        description: vehicleData[i].description
    }
});

Finally, let the click event search for the graphic, like this,

map.on("click", function(event) {
    map.popup.open({
        location: event.mapPoint,
        fetchFeatures: true
    });
});

BTW, I just keep the last step because you change default on purpose, I am not seeing the reason here but you must have one.

Solution 2:

@cabesuon is right. you can remove the on click event and remove map.popup.autoOpenEnabled = false; too. after that clicking on the graphic will open the popup info by default.

for the table format you may want to use a function for content

    // The following snippet shows how to use a function
    // to create a simple node and display it in the popup template content
    let template = new PopupTemplate({
      title: "Population by Gender",
      content: setContentInfo
    });
    
    function setContentInfo(feature){ // feature here is the graphic, you may access its properties for the table
      // create a chart for example
      let node = domConstruct.create("div", { innerHTML: "Text Element inside an HTML div element." });
      return node;
    }