Hey Team!
So, long story short, I'm creating an application that allows users to adopt road segments as the OOTB Esri option won't work for our needs. I've got to the point where users can click on the app, a form gets created and populated, they can input the necessary information, and apply the edits. However, as it stands, users can only select one feature at a time, which won't work.
I need users to be able to select multiple features on a map, fill out one form, and have the fields in the form be applied as unique edits to each of the selected features. The testing code block is below:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Update FeatureLayer using applyEdits() - 4.6</title>
<link rel="stylesheet" href="https://js.arcgis.com/4.6/esri/css/main.css">
<script src="https://js.arcgis.com/4.6/"></script>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
.editArea-container {
background: #fff;
font-family: "Avenir Next W00", "Helvetica Neue", Helvetica, Arial, sans-serif;
line-height: 1.5em;
overflow: auto;
padding: 12px 15px;
width: 300px;
}
.edit-button:hover,
.edit-button:focus {
background-color: #e4e4e4;
color: #0079c1;
cursor:pointer;
}
.inputInfo {
font-size: 12px;
height: 32px;
margin-bottom: 6px;
padding: 0 6px;
width: 100%;
}
.list-heading {
font-weight: normal;
margin-top: 20px;
margin-bottom: 10px;
color: #323232;
}
.edit-button {
font-size: 14px;
height: 32px;
margin-top: 10px;
width: 100%;
background-color: #0079c1;
border: 1px solid #451F78;
color: #FFFFFF;
}
.or-wrap {
background-color: #e0e0e0;
height: 1px;
margin: 2em 0;
overflow: visible;
}
.or-text {
background: #fff;
line-height: 0;
padding: 0 1em;
position: relative;
top: -.75em;
}
input:invalid {
border: 1px solid red;
}
input:valid {
border: 1px solid green;
}
</style>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/Layer",
"esri/Graphic",
"esri/widgets/Expand",
"esri/widgets/Home",
"esri/widgets/Search",
"esri/geometry/Extent",
"esri/Viewpoint",
"esri/core/watchUtils",
"dojo/on",
"dojo/dom",
"dojo/domReady!"
],
function(
Map, MapView, Layer, Graphic, Expand,
Home, Search, Extent, Viewpoint, watchUtils,
on, dom
) {
var featureLayer, editExpand;
var editArea, attributeEditing, inputDescription, inputOrg, inputSign, inputName, inputAddress, inputCity, inputState, inputZip, inputPhone,
inputUserInfo, updateInstructionDiv;
var map = new Map({
basemap: "topo"
});
var searchWidget = new Search({
view: view
});
var initialExtent = new Extent({
xmin: -9006905,
xmax: -8992793,
ymin: 4191052,
ymax: 4199068,
spatialReference: 102100
});
var view = new MapView({
container: "viewDiv",
map: map,
extent: initialExtent
});
Layer.fromPortalItem({
portalItem: {
id: "821542fffc1c4fc6b38297d7b9df4567"
}
}).then(addLayer)
.otherwise(handleLayerLoadError);
setupEditing();
setupView();
function addLayer(lyr) {
featureLayer = lyr;
map.add(lyr);
}
function applyEdits(params) {
unselectFeature();
var promise = featureLayer.applyEdits(params);
editResultsHandler(promise);
}
function editResultsHandler(promise) {
promise
.then(function(editsResult) {
var extractObjectId = function(result) {
return result.objectId;
};
if (editsResult.addFeatureResults.length > 0) {
var adds = editsResult.addFeatureResults.map(
extractObjectId);
newIncidentId = adds[0];
selectFeature(newIncidentId);
}
})
.otherwise(function(error) {
console.log("===============================================");
console.error("[ applyEdits ] FAILURE: ", error.code, error.name,
error.message);
console.log("error = ", error);
});
}
view.on("click", function(evt) {
unselectFeature();
view.hitTest(evt).then(function(response) {
if (response.results.length > 0 && response.results[0].graphic) {
var feature = response.results[0].graphic;
selectFeature(feature.attributes[featureLayer.objectIdField]);
inputDescription.value = feature.attributes[
"FULL_NAME"];
inputOrg.value = feature.attributes[
"Org_Name"];
inputSign.value = feature.attributes[
"Sign_Verbage"];
inputName.value = feature.attributes[
"ContactName"];
inputAddress.value = feature.attributes[
"OrgAddress"];
inputCity.value = feature.attributes[
"OrgCity"];
inputState.value = feature.attributes[
"OrgState"];
inputZip.value = feature.attributes[
"OrgZip"];
inputPhone.value = feature.attributes[
"OrgPhone"];
inputUserInfo.value = feature.attributes[
"Email"];
attributeEditing.style.display = "block";
updateInstructionDiv.style.display = "none";
}
});
});
function selectFeature(objectId) {
var selectionSymbol = {
type: "simple-marker",
color: [0, 0, 0, 0],
style: "square",
size: "40px",
outline: {
color: [0, 255, 255, 1],
width: "3px"
}
};
var query = featureLayer.createQuery();
query.where = featureLayer.objectIdField + " = " + objectId;
featureLayer.queryFeatures(query).then(function(results) {
if (results.features.length > 0) {
editFeature = results.features[0];
editFeature.symbol = selectionSymbol;
view.graphics.add(editFeature);
}
});
}
function unselectFeature() {
attributeEditing.style.display = "none";
updateInstructionDiv.style.display = "block";
inputDescription.value = null;
inputOrg.value = null;
inputSign.value = null;
inputName.value = null;
inputAddress.value = null;
inputCity.value = null;
inputState.value = null;
inputZip.value = null;
inputPhone.value = null;
inputUserInfo.value = null;
view.graphics.removeAll();
}
function setupView() {
var homeButton = new Home({
view: view,
viewpoint: new Viewpoint({
targetGeometry: initialExtent
})
});
editExpand = new Expand({
expandIconClass: "esri-icon-edit",
expandTooltip: "Expand Edit",
expanded: true,
view: view,
content: editArea
});
view.ui.add([
{
component: searchWidget,
position: "top-left",
index: 0
}, {
component: homeButton,
position: "top-left"
}, {
component: editExpand,
position: "top-right",
}
]);
}
function setupEditing() {
editArea = dom.byId("editArea");
updateInstructionDiv = dom.byId("updateInstructionDiv");
attributeEditing = dom.byId("featureUpdateDiv");
inputDescription = dom.byId("inputDescription");
inputOrg = dom.byId("inputOrg");
inputSign = dom.byId("inputSign");
inputName = dom.byId("inputName");
inputAddress = dom.byId("inputAddress");
inputCity = dom.byId("inputCity");
inputState = dom.byId("inputState");
inputZip = dom.byId("inputZip");
inputPhone = dom.byId("inputPhone");
inputUserInfo = dom.byId("inputUserInfo");
on(dom.byId("btnUpdate"), "click", function(evt) {
if (editFeature) {
editFeature.attributes["FULL_NAME"] = inputDescription.value;
var edits = {
updateFeatures: [editFeature]
};
applyEdits(edits);
}
});
on(dom.byId("btnAddFeature"), "click", function() {
unselectFeature();
on.once(view, "click", function(event) {
event.stopPropagation();
if (event.mapPoint) {
point = event.mapPoint.clone();
point.z = undefined;
point.hasZ = false;
newIncident = new Graphic({
geometry: point,
attributes: {}
});
var edits = {
addFeatures: [newIncident]
};
applyEdits(edits);
attributeEditing.style.display = "block";
updateInstructionDiv.style.display = "none";
dom.byId("viewDiv").style.cursor = "auto";
}
else {
console.error("event.mapPoint is not defined");
}
});
dom.byId("viewDiv").style.cursor = "crosshair";
editArea.style.cursor = "auto";
});
on(dom.byId("btnDelete"), "click", function() {
window.open("https://survey123.arcgis.com/share/5e8d603ed41a4e49b99c420a32a9e8e7")
});
view.when(function() {
watchUtils.whenTrue(view, "stationary", function() {
if (editExpand) {
if (view.zoom <= 12) {
editExpand.domNode.style.display = "none";
}
else {
editExpand.domNode.style.display = "block";
}
}
});
});
}
function handleLayerLoadError(err) {
console.log("Layer failed to load: ", err);
}
});
</script>
</head>
<body>
<div id="editArea" class="editArea-container">
<div id="addFeatureDiv" style="overflow:auto">
<h3 class="list-heading">Charlotte's Adopt A City Street</h3>
<ul style="font-size: 13px; padding-left: 1.5em;">
<li>To Adopt Available Streets, click the 'Start Adopting' Button</li>
<li>To Submit Your Cleanup Report, click the 'Submit Cleanup Report' Button</li>
</ul>
<input type="button" class="edit-button" value="Start Adopting" id="btnAddFeature">
</div>
<div id="updateInstructionDiv" style="text-align:center">
<p class="or-wrap"><span class="or-text">Or</span></p>
<input type="button" class="edit-button" value="Submit Cleanup Report" id="btnDelete">
</div>
<div id="featureUpdateDiv" style="display:none; margin-top: 1em">
<h3 class="list-heading">Enter Your Information Below</h3>
<div id="attributeArea">
<label for="inputDescription">Selected Streets:</label>
<input class="inputInfo" required disabled type="text" id="inputDescription" placeHolder="Streets Selected"><br>
<label for="inputOrg">Organization Name:</label>
<input class="inputInfo" required type="text" id="inputOrg" placeHolder="Enter organization name"><br>
<label for="inputSign">Adopt-A-Street Sign Text:</label>
<input class="inputInfo" required type="text" maxlength="34" id="inputSign" placeHolder="Enter the text you'd like on your sign"><br>
<label for="inputName">Name (First, Last):</label>
<input class="inputInfo" required type="text" id="inputName" placeHolder="Enter your name (first and last)"><br>
<label for="inputAddress">Street Address:</label>
<input class="inputInfo" required type="text" id="inputAddress" placeHolder="Enter your address"><br>
<label for="inputCity">City:</label>
<input class="inputInfo" required type="text" id="inputCity" placeHolder="Enter your city"><br>
<label for="inputState">State:</label>
<input class="inputInfo" required type="text" maxlength="2" id="inputState" placeHolder="Enter your state"><br>
<label for="inputZip">Zip Code:</label>
<input class="inputInfo" required type="number" maxlength="5" id="inputZip" placeHolder="Enter your zip code"><br>
<label for="inputPhone">Phone Number:</label>
<input class="inputInfo" required type="text" maxlength="15" id="inputPhone" placeHolder="Enter your phone number"><br>
<label for="inputUserInfo">Email Address:</label>
<input class="inputInfo" required type="email" name="email" id="inputUserInfo" pattern="[^ @]*@[^ @]*"
placeHolder="Enter email address"><br>
<input type="button" class="edit-button" value="Submit Adoption Request" id="btnUpdate">
</div>
<div id="deleteArea">
</div>
</div>
</div>
<div id="viewDiv"></div>
</body>
</html>