When I am zoomed out so that the popup template has multiple items,the items after the first item (see attached image) do not have the attributes. They come back as undefined.
Here is the code to duplicate it.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Get Data Grid </title>
<link rel="stylesheet" href="https://js.arcgis.com/4.14/esri/css/main.css">
<script src="https://js.arcgis.com/4.14/"></script>
</head>
<body>
<div class="container body-content">
<script>
function generateRenderer() {
if (legendOn) {
var typeParams = {
layer: csvLayer,
numTypes: -1,
field: "ClassName",
view: view,
legendOptions: {
title: "VGS Data Points"
}
};
typeCreatorProxy
.createRenderer(typeParams)
.then(function (response) {
// set the renderer to the layer and add it to the map
csvLayer.renderer = response.renderer;
//map.add(csvLayer);
})
.catch(function (error) {
console.error("there was an error: ", error);
});
} else {
var typeParams = {
layer: csvLayer,
numTypes: 0,
field: "ClassName",
view: view,
legendOptions: {
title: "VGS Data Points"
}
};
typeCreatorProxy
.createRenderer(typeParams)
.then(function (response) {
// set the renderer to the layer and add it to the map
csvLayer.renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-marker", // autocasts as new SimpleMarkerSymbol()
size: 6,
color: "#0c234b",
outline: { // autocasts as new SimpleLineSymbol()
width: 0.5,
color: "white"
}
}
};
//map.add(csvLayer);
})
.catch(function (error) {
console.error("there was an error: ", error);
});
}
}
let map,
view,
csvLayer,
csvLayerView,
polygonGraphicsLayer,
sketchViewModel,
highlight,
grid,
legend,
typeCreatorProxy,
simpleRendererProxy,
labelClass;
function RunMap() {
require([
"esri/Map",
"esri/layers/CSVLayer",
"esri/views/MapView",
"esri/layers/GraphicsLayer",
"esri/widgets/Sketch/SketchViewModel",
"dgrid/OnDemandGrid",
"dgrid/extensions/ColumnHider",
"esri/Graphic",
"dstore/legacy/StoreAdapter",
"dojo/store/Memory",
"dgrid/Selection",
"esri/core/urlUtils",
"esri/layers/FeatureLayer",
"esri/PopupTemplate",
"esri/widgets/Legend",
"esri/renderers/smartMapping/creators/type",
"esri/renderers/SimpleRenderer",
"esri/symbols/SimpleLineSymbol",
"esri/Color",
"esri/symbols/SimpleFillSymbol",
"esri/widgets/Print",
"esri/layers/support/LabelClass",
"esri/core/promiseUtils",
"dojo/domReady!"
],
function (Map,
CSVLayer,
MapView,
GraphicsLayer,
SketchViewModel,
OnDemandGrid,
ColumnHider,
Graphic,
StoreAdapter,
Memory,
Selection,
urlUtils,
FeatureLayer,
PopupTemplate,
Legend,
typeRendererCreator,
SimpleRenderer,
SimpleLineSymbol,
Color,
SimpleFillSymbol,
Print,
LabelClass,
promiseUtils) {
typeCreatorProxy = typeRendererCreator;
simpleRendererProxy = new SimpleRenderer();
const url = "data.csv";
function blankIfUndefined(item) {
if (item == undefined) {
return "";
} else {
return item;
}
}
const template_dot = new PopupTemplate(
{
title: "Site {SiteName}",
outfields: ["*"],
content: function (data) {
///debugger;
// if (data.graphic.attributes.FK_Site == 0) {
var br = document.createElement("DIV");
br.innerHTML = "<br/>";
//site edit icon
var icon = document.createElement("I");
icon.className = 'fa fa-info-circle';
icon.style = 'font-size: 32px;vertical-align:bottom';
icon.title = 'View Site Details';
icon.innerHTML = " ";
//site edit url
var siteEditUrl = document.createElement("A");
siteEditUrl.style = 'color:#8b0015';
siteEditUrl.href = "/Containers/viewSite/63448eb6-c585-4f19-9b2c-ae5d5a0c2dc2/" + data.graphic.attributes.PK_SiteClass + "/" + data.graphic.attributes.FK_Site;
siteEditUrl.target = "_new";
siteEditUrl.append(icon);
//report icon
var dashimage = document.createElement("IMG");
dashimage.src="/Content/Images/ReportDash.svg";
dashimage.style = "height:28px";
//report link
var aref = document.createElement("A");
aref.href = "/ReportExport/Dashboard3/63448eb6-c585-4f19-9b2c-ae5d5a0c2dc2/" +
data.graphic.attributes.FK_Site;
//aref.className = "btn btn-default";
aref.target = "_new";
aref.title = "View Report Dashboard";
aref.append(dashimage);
//FOLDER
var div = document.createElement("DIV");
div.append(siteEditUrl);
div.appendChild(aref);
div.appendChild(br);
var folder = document.createElement("DIV");
folder.innerHTML = "<b>Folder:</b> " + data.graphic.attributes.ClassName;
folder.style = "padding-bottom:5px;";
div.appendChild(br);
div.appendChild(folder);
//Date Established
var dateToUse = "" + data.graphic.attributes.Date;
dateToUse = dateToUse.replace("x", "");
var dateEstablished = document.createElement("DIV");
dateEstablished.innerHTML = "<b>Established:</b>" + dateToUse;
dateEstablished.style = "padding-bottom:5px;";
div.appendChild(dateEstablished);
var coordinates = document.createElement("DIV");
coordinates.innerHTML = "<b>Coordinates:</b> Long: " +
data.graphic.attributes.longitude +
" Lat:" +
data.graphic.attributes.latitude;
coordinates.style = "padding-bottom:5px;";
div.appendChild(coordinates);
var evelation = document.createElement("DIV");
evelation.innerHTML = "<b>Elevation:</b> " + data.graphic.attributes.Elevation;
evelation.style = "padding-bottom:5px;";
div.appendChild(evelation);
var description = document.createElement("DIV");
description.innerHTML = "<b>Description:</b> " + data.graphic.attributes.Description;
div.appendChild(description);
return div;
}
//content:popupResult
});
const gridDiv = document.getElementById("grid");
const infoDiv = document.getElementById("info");
const gridFields = [
"__OBJECTID", "latitude", "longitude",
"ClassName", "SiteName", "Description"
];
const dataStore = new StoreAdapter({
objectStore: new Memory({
idProperty: "__OBJECTID"
})
});
csvLayer = new CSVLayer({
url: url,
copyright: "University of Arizona",
title: "VGS Data Points",
popupTemplate: template_dot,
objectIdField: "__OBJECTID",
});
map = new Map({
basemap: "topo",
layers: [csvLayer]
});
view = new MapView({
container: "viewDiv",
center: [-113.5, 36.7],
zoom: 10,
map: map
});
csvLayer.when(function () {
const featureLayer = map.layers.getItemAt(0);
try {
const x = csvLayer.fullExtent.center.x;
view.goTo(csvLayer.fullExtent);
const queryParams = csvLayer.createQuery();
queryParams.geometry = csvLayer.fullExtent;
queryParams.where = queryParams.where + " AND 1=1";
csvLayer.queryFeatures(queryParams).then(function (results) {
const graphics = results.features;
const data = graphics.map(function (feature, i) {
return Object.keys(feature.attributes)
.filter(function (key) {
// get fields that exist in the grid
return (gridFields.indexOf(key) !== -1);
})
// need to create key value pairs from the feature
// attributes so that info can be displayed in the grid
.reduce(function (obj, key) {
obj[key] = feature.attributes[key];
return obj;
},
{});
});
// set the datastore for the grid using the
// attributes we got for the query results
dataStore.objectStore.data = data;
grid.set("collection", dataStore);
});
} catch (ex) {
window.alert("There are no sites in this folder with locations attached");
}
createGrid(csvLayer.fields);
view.whenLayerView(csvLayer).then(function (layerView) {
csvLayerView = layerView;
});
}).catch(errorCallback);;
function selectFeatureFromGrid(event) {
// close view popup if it is open
view.popup.close();
// get the ObjectID value from the clicked row
const row = event.rows[0];
const id = row.data.__OBJECTID;
// setup a query by specifying objectIds
const query = {
objectIds: [parseInt(id)],
outFields: ["*"],
returnGeometry: true
};
// query the csvLayerView using the query set above
csvLayerView.queryFeatures(query).then(function (results) {
const graphics = results.features;
// remove all graphics to make sure no selected graphics
view.graphics.removeAll();
// create a new selected graphic
const selectedGraphic = new Graphic({
geometry: graphics[0].geometry,
symbol: {
type: "simple-marker",
style: "square",
color: "purple",
size: "14px", // pixels
outline: { // autocasts as new SimpleLineSymbol()
color: [255, 255, 0],
width: 2 // points
}
}
});
// add the selected graphic to the view
// this graphic corresponds to the row that was clicked
view.graphics.add(selectedGraphic);
})
.catch(errorCallback);
}
function createGrid(fields) {
const columns = fields.filter(function (field, i) {
if (gridFields.indexOf(field.name) !== -1) {
return field;
}
}).map(function (field) {
if (field.name === "__OBJECTID") {
return {
field: field.name,
label: field.name,
sortable: true,
hidden: true
};
} else {
return {
field: field.name,
label: field.alias,
sortable: true
};
}
});
// create a new onDemandGrid with its selection and columnhider
// extensions. Set the columns of the grid to display attributes
// for the layer
grid = new (OnDemandGrid.createSubclass([Selection, ColumnHider]))({
columns: columns
},
"grid");
// add a row-click listener on the grid. This will be used
// to highlight the corresponding feature on the view
grid.on("dgrid-select", selectFeatureFromGrid);
}
function clearUpSelection() {
view.graphics.removeAll();
// grid.clearSelection();
}
function errorCallback(error) {
console.log("error:", error);
}
});
}
RunMap();
</script>
</div>
<div id="info">
<!------------- MAP VIEW-->
<div id="viewDiv" class="col-lg-12" style="height: 800px; width: 100%;">
<!------------- FILTER BUTTON-->
<div id="select-by-polygon" class="esri-widget esri-widget--button esri-widget esri-interactive"
title="Select features by polygon">
<span class="fas fa-filter"></span>
</div>
</div>
<!----------------------GRID HTML-->
</div>
<br/>
<div id="showAttributesDiv" style="width:100%">
<div id="gridDisplay">
<span class="info" id="featureCount"></span>
<div id="grid"></div>
</div>
</div>
<style>
.navbar-inverse .navbar-nav > li > a {
color: white;
}
.navbar-inverse .navbar-link {
color: white;
}
.navbar-inverse {
background-color: green;
}
.dropdown-menu {
background-color: green;
}
.panel-primary > .panel-heading {
background-color: green;
color: white;
}
.navbar-toggle {
background-color: green;
color: white;
}
btn {
background-color: green;
color: white;
}
input.btn-primary {
background-color: green;
color: white;
}
button.btn-primary:hover {
background-color: white color: green;
}
input.btn-primary:hover {
background-color: white color: green;
}
button.btn-primary {
background-color: green;
color: white;
}
input.btn-default {
background-color: green;
color: white;
}
input.btn-default:hover {
background-color:;
white color:green;
}
</style>
</body>
</html>
I have also included a CSV file in the attachments to duplicate the error.
Solved! Go to Solution.
Hi Don,
OK I looked at your app and thank you for the simple reproducible case. I had to recruit couple my coworkers to figure why it wasn't working especially the first one. I would have never caught it. 😀
So there are couple of issues in the app. First issue is the following. Notice that outfields has lower case f. You need to change it to outFields.
const template_dot = new PopupTemplate({
title: "Site {SiteName}",
outfields: ["*"],
content: ...
});
That still did not solve the problem. I narrowed this down to a data issue. CSV file has a field called __ObjectId. This is causing the same issue as the above. To workaround this issue, please rename this field to Id or just remove it. CSVLayer assign objectID to your features. I have created an issue for this. Will let you know once we fix it.
Here is your app in a codepen and is working expected now.
Please do not hesitate to reach out to me if you have more questions.
-Undral
Hi Don,
OK I looked at your app and thank you for the simple reproducible case. I had to recruit couple my coworkers to figure why it wasn't working especially the first one. I would have never caught it. 😀
So there are couple of issues in the app. First issue is the following. Notice that outfields has lower case f. You need to change it to outFields.
const template_dot = new PopupTemplate({
title: "Site {SiteName}",
outfields: ["*"],
content: ...
});
That still did not solve the problem. I narrowed this down to a data issue. CSV file has a field called __ObjectId. This is causing the same issue as the above. To workaround this issue, please rename this field to Id or just remove it. CSVLayer assign objectID to your features. I have created an issue for this. Will let you know once we fix it.
Here is your app in a codepen and is working expected now.
Please do not hesitate to reach out to me if you have more questions.
-Undral
I see the fix worked in the demo. I have moved to the real page (which is way more complex) and it doesn't seem to do multiple items in the popup template no matter how far I zoom back. So it is fixed, a little odd, but fixed.
Thank you
Have you deleted the objectId column from the csv file you are using for the real site? Once I deleted it the column, I started seeing the multiple items.
Yea, I did it all. It is just I can't get the original multiple popup templates to happen ever. So technically I can't test the solution because I can't do the conditions but I am calling it good. I was able to get rid of all the code that was calling back to the database to get items past that first template in my actual application. So in my mind, mission accomplished.
Hi there,
I just want to give you a quick on this. We fixed this issue at JS API version 4.22. This version will be released end of December. The popup will display for all overlapping features without you having to do anything once you migrate to 4.22.
Thanks,
-Undral