javascriptesriarcgis-js-apiesri-mapsesri-arc-engine

Issue when displaying a Popup window in the ESRI Map


Currently, my Esri Map is displaying the locations on the Esri Map as pinpoints after I pass the location details(latitude, longitude, etc..) to the Esri Map.

So, now what I wanted is when a user clicks on a specific pinpoint, I want to show a popup template and display a table containing its Address, longitude, latitude, etc. I want to dynamically iterate through the array of location objects which I already have(locationData) and set popupTemplate title, content, feildInfo, fieldName etc.

Here is what I have done and I'm getting the following console error now.

const popUpTemplate = new PopupTemplate({
title: '',
content: locationData.map((d,i)=>(
[
  {
    type:"fields",
    fieldInfos: [
      {
          fieldName: d.address,
          label: "Address"
      },
      {
          fieldName: d.latitude,
          label: "Latitude",
          format: {
              places: 2
          }
      },
      {
          fieldName: d.longitude,
          label: "Longitude",
          format: {
              places: 2
          }
      }
    ]
  },
  new CustomContent({
    outFields: ["*"],
    creator: (event) => {
        const a = document.createElement("a");
        // a.href = event.graphic.attributes.url;
        a.target = "_blank";
        // a.innerText = event.graphic.attributes.url;
        return a;
    }
 })
 ]
 ))
});



const dataFeedLayer = new FeatureLayer({
 source: horizonData.map((d,i)=>(
  {
      geometry: new Point({
        longitude: d.longitude,
        latitude: d.latitude
      }),
      attributes: {
        ObjectID: i,
        ...d
      }
  }
)),
fields: [
  {
      name: "ObjectID",
      alias: "ObjectID",
      type: "oid"
  },
  {
      name: "name",
      alias: "Name",
      type: "string"
  },
  {
      name: "addrs",
      alias: "addrs",
      type: "string"
  },
  {
      name: "url",
      alias: "url",
      type: "string"
  },
  {
      name: "lat",
      alias: "Latitude",
      type: "double"
  },
  {
      name: "lon",
      alias: "Longitude",
      type: "double"
  }
],
 objectIdField: 'ObjectID',
 geometryType: "point",
 renderer: renderer,
 popupTemplate: popUpTemplate,
});

webmap.add(dataFeedLayer);

[esri.core.Accessor] Accessor#set Invalid property value, value needs to be one of 'esri.popup.content.MediaContent', 'esri.popup.content.CustomContent', 'esri.popup.content.TextContent', 'esri.popup.content.AttachmentsContent', 'esri.popup.content.FieldsContent', or a plain object that can autocast (having .type = 'media', 'custom', 'text', 'attachments', 'fields')

Any idea on how to resolve this. Thanks in advance.


Solution

  • You need to think of the popup template as a descriptor for individual features. As the name implied, is a template for presenting the information of a single feature.

    In that way the correct content for the popup template in your code should be,

    {
        type: "fields",
        fieldInfos: [
            {
                fieldName: "addrs",
                label: "Address"
            },
            {
                fieldName: "lat",
                label: "Latitude",
                format: {
                    places: 2
                }
            },
            {
                fieldName: "lon",
                label: "Longitude",
                format: {
                    places: 2
                }
            }
        ]
    }
    
    new CustomContent({
        outFields: ["*"],
        creator: (event) => {
            const a = document.createElement("a");
            a.href = event.graphic.attributes.url;
            a.target = "_blank";
            a.innerText = event.graphic.attributes.url;
            return a;
        }
    })
    

    Now, for the title of the popup, you can use a fixed text or a variable text. The variable option will depend on the values of the feature attributes. You do this with the field names between curly brackets, examples: "{name}", "Name: {name}", "{name} is so amazing!!!".

    Resuming, the full definition for the popup content should be,

    const popUpTemplate = new PopupTemplate({
        title: "{name}",
        content: [
            {
                type: "fields",
                fieldInfos: [
                    {
                        fieldName: "addrs",
                        label: "Address"
                    },
                    {
                        fieldName: "lat",
                        label: "Latitude",
                        format: {
                            places: 2
                        }
                    },
                    {
                        fieldName: "lon",
                        label: "Longitude",
                        format: {
                            places: 2
                        }
                    }
                ]
            },
            new CustomContent({
                outFields: ["*"],
                creator: (event) => {
                    const a = document.createElement("a");
                    a.href = event.graphic.attributes.url;
                    a.target = "_blank";
                    a.innerText = event.graphic.attributes.url;
                    return a;
                }
            })
        ],
        outFields: ["*"]
    });
    

    EDIT on @HarshaW comment: Base on the API docs it is as you mention, that is, the parameter for creator function it is of type Graphic, not {graphic:Graphic}. So to solve your error change the CustomContent to,

    new CustomContent({
        outFields: ["*"],
        creator: (graphic) => {
            const a = document.createElement("a");
            a.href = graphic.attributes.url;
            a.target = "_blank";
            a.innerText = graphic.attributes.url;
            return a;
        }
    })
    

    Now, if you check this example (also from the documentation) or this answer, you will notice that it is like first solution.

    I am not sure why is this, maybe someone else can give us more inside on it.

    In the meantime, just check which one works and use it. If you need something more safe and you do not care for an extra check,

    new CustomContent({
        outFields: ["*"],
        creator: (eventOrGraphic) => {
            const graphic = eventOrGraphic instanceof Graphic ? eventOrGraphic : eventOrGraphic.graphic;
            const a = document.createElement("a");
            a.href = graphic.attributes.url;
            a.target = "_blank";
            a.innerText = graphic.attributes.url;
            return a;
        }
    })