Hello,
I am using ArcGIS API 4 and am trying to combine filters. I have a featureLayer that is filtered depending on the zoom level and then can also be filtered with a dropdown but the problem is that these filters override each other. I would like them to be dependent on one another. If the zoom filter is set on the layer, it should remain applied if the dropdown menu is set. I can't find an example of how to to set this up. Any help would be highly appreciated.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="https://js.arcgis.com/4.17/esri/css/main.css">
<script src="https://js.arcgis.com/4.17/"></script>
<title>UWM Historical Nautical Charts</title>
<style>
html, body, #viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<script>
require(["esri/Map", "esri/views/MapView", "esri/layers/FeatureLayer", "esri/geometry/Extent"], function(
Map,
MapView,
FeatureLayer,
Extent
) {
// Create a style for the chartsLayer
var renderer = {
type: "simple", // autocasts as new SimpleRenderer()
symbol: {
type: "simple-fill", // autocasts as new SimpleFillSymbol()
color: [ 255, 128, 0, 0.5 ],
outline: { // autocasts as new SimpleLineSymbol()
width: 1,
color: "white"
}
}
};
// Create a FeatureLayer
var chartsLayer = new FeatureLayer({
url: "https://webgis.uwm.edu/arcgisuwm/rest/services/AGSL/agsl_nautical/MapServer/0",
outFields: ["*"], // Return all fields so it can be queried client-side
renderer: renderer
});
// Create the Map and add the featureLayer defined above
map = new Map({
basemap: "oceans",
layers: [chartsLayer]
});
// Create the MapView
var view = new MapView({
container: "viewDiv",
map: map,
center: [0,0],
zoom: 2
});
// setup the contraints of the map
view.constraints = {
geometry: { // Constrain lateral movement to the entire globe with no repeat
type: "extent",
xmin: -90,
ymin: -180,
xmax: 90,
ymax: 180
},
minZoom: 2,
rotationEnabled: false // Disables map rotation
};
// Create a template for the popup
var template = {
// autocasts as new PopupTemplate()
title: "{title}",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "label",
label: "label"
},
{
fieldName: "west",
label: "West"
},
{
fieldName: "east",
label: "East"
},
{
fieldName: "north",
label: "North"
},
{
fieldName: "south",
label: "South"
},
{
fieldName: "scale",
label: "Scale"
}
]
}
]
};
// Set the popup template on the layer
chartsLayer.popupTemplate = template;
function setFeatureLayerFilter(expression) {
chartsLayer.definitionExpression = expression;
}
// The filter for the page load map view
// Only show small scale series
setFeatureLayerFilter("Shape_Area >= 9463642202000" );
//setFeatureLayerFilter("scale < 698000" );
// Exclude map scales according to the zoom level
// Use 'Shape_Area' because scale information might be missing for some charts
view.watch("zoom", function(newValue) {
if (newValue <= 2) {
setFeatureLayerFilter("Shape_Area >= 9463642202000" );
} else if (newValue >= 4) {
setFeatureLayerFilter("Shape_Area <= 946364220200" );
}
console.log("scale property changed: ", newValue);
});
// Query the layer based on the chart series
var sqlExpressions = [
"datePub = 1911",
"datePub = 1912"
];
var selectFilter = document.createElement("select");
selectFilter.setAttribute("class", "esri-widget esri-select");
selectFilter.setAttribute(
"style",
"width: 275px; font-family: Avenir Next W00; font-size: 1em;"
);
sqlExpressions.forEach(function (sql) {
var option = document.createElement("option");
option.value = sql;
option.innerHTML = sql;
selectFilter.appendChild(option);
});
view.ui.add(selectFilter, "top-right");
selectFilter.addEventListener('change', function (event) {
setFeatureLayerFilter(event.target.value);
});
});
</script>
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
Solved! Go to Solution.
Hi there,
You have to make each of your listener functions listen to each other.
Here's what I did to make it work (nb I changed the dates to 1856 and 1921 because they were easier to see):
function setFeatureLayerFilter(expression) {
chartsLayer.definitionExpression = expression;
}
// The filter for the page load map view
// Only show small scale series
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND datepub = 1856");
//setFeatureLayerFilter("scale < 698000" );
// Exclude map scales according to the zoom level
// Use 'Shape_Area' because scale information might be missing for some charts
view.watch("zoom", function(newValue) {
switch (selectFilter.value) {
case "datePub = 1856":
if (newValue <= 2) {
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND datePub = 1856");
} else if (newValue >= 4) {
setFeatureLayerFilter("Shape_Area <= 946364220200 AND datePub = 1856");
}
break;
case "datePub = 1921":
if (newValue <= 2) {
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND datePub = 1921");
} else if (newValue >= 4) {
setFeatureLayerFilter("Shape_Area <= 946364220200 AND datePub = 1921");
}
break;
}
});
// Query the layer based on the chart series
var sqlExpressions = [
"datePub = 1856",
"datePub = 1921"
];
var selectFilter = document.createElement("select");
selectFilter.setAttribute("class", "esri-widget esri-select");
selectFilter.setAttribute(
"style",
"width: 275px; font-family: Avenir Next W00; font-size: 1em;"
);
sqlExpressions.forEach(function(sql) {
var option = document.createElement("option");
option.value = sql;
option.innerHTML = sql;
selectFilter.appendChild(option);
});
view.ui.add(selectFilter, "top-right");
selectFilter.addEventListener('change', function(event) {
if (view.zoom >= 2) {
setFeatureLayerFilter("Shape_Area <= 9463642202000 AND" + event.target.value);
} else {
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND" + event.target.value);
}
});
Hi there,
You have to make each of your listener functions listen to each other.
Here's what I did to make it work (nb I changed the dates to 1856 and 1921 because they were easier to see):
function setFeatureLayerFilter(expression) {
chartsLayer.definitionExpression = expression;
}
// The filter for the page load map view
// Only show small scale series
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND datepub = 1856");
//setFeatureLayerFilter("scale < 698000" );
// Exclude map scales according to the zoom level
// Use 'Shape_Area' because scale information might be missing for some charts
view.watch("zoom", function(newValue) {
switch (selectFilter.value) {
case "datePub = 1856":
if (newValue <= 2) {
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND datePub = 1856");
} else if (newValue >= 4) {
setFeatureLayerFilter("Shape_Area <= 946364220200 AND datePub = 1856");
}
break;
case "datePub = 1921":
if (newValue <= 2) {
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND datePub = 1921");
} else if (newValue >= 4) {
setFeatureLayerFilter("Shape_Area <= 946364220200 AND datePub = 1921");
}
break;
}
});
// Query the layer based on the chart series
var sqlExpressions = [
"datePub = 1856",
"datePub = 1921"
];
var selectFilter = document.createElement("select");
selectFilter.setAttribute("class", "esri-widget esri-select");
selectFilter.setAttribute(
"style",
"width: 275px; font-family: Avenir Next W00; font-size: 1em;"
);
sqlExpressions.forEach(function(sql) {
var option = document.createElement("option");
option.value = sql;
option.innerHTML = sql;
selectFilter.appendChild(option);
});
view.ui.add(selectFilter, "top-right");
selectFilter.addEventListener('change', function(event) {
if (view.zoom >= 2) {
setFeatureLayerFilter("Shape_Area <= 9463642202000 AND" + event.target.value);
} else {
setFeatureLayerFilter("Shape_Area >= 9463642202000 AND" + event.target.value);
}
});
Sorry to be late on getting back to you on this. This works great, thank you very much.