Turns out it's not that much different from what we did the last time. This post will describe how we went about it.
JS Bin on jsbin.com
Once again, the objective was to edit attributes of features from a Feature Layer without the confines of a map container.
A basic HTML form was created on a blank page where they could make changes to features without having to see them on a map - choosing instead to reference them on the basis of IDs which are part of their attributes. So what did we do different? Very few things actually.
For starters since we did not have the advantage of having the attribute inspector load up all our required fields, we created the html form for data input as shown below:
Choose Work ID:
As you can see, actual field inputs needed to be placed in. I did not place them in an organized manner in this example but I hope you get the general idea of what I was doing. One may notice that the first two inputs are actually dojo comboBoxes. These are the fields that had coded values as domains and thus required only predetermined values to be entered. We therefore had to populate the comboBoxes with values from the feature service. We did this by querying the feature service for coded domain values and loading them into a datastore that feeds the comboBox as shown below:
//Now query to get distinct values for Project Type // query distinct use code values from parcels var queryTask = new QueryTask(url); var query = new Query(); query.where = "PROJTYPE is not null"; // query for non-null values query.orderByFields = ["PROJTYPE"]; // sort it so we won't have to later query.returnGeometry = false; // turn geometry off, required to be false when using returnDistinctValues query.returnDistinctValues = true; query.outFields = ["PROJTYPE"]; queryTask.execute(query, function(results){ var resultItems = []; var resultCount = results.features.length; var store2 = new Memory({data:[]}); dijit.byId("uniqueValuesSelect").set('store',store2); var data = array.map(results.features,lang.hitch(this,function(info,index){ var value = info.attributes.PROJTYPE; console.log(info); var dataItem = { id:index, name:value }; return dataItem; })); store2 = new Memory({data:data}); dijit.byId("uniqueValuesSelect").set('store',store2); }); //Now query to get distinct values for Work Status // query distinct use code values from parcels var queryTask2 = new QueryTask(url); var query2 = new Query(); query2.where = "WORKSTATUS is not null"; // query for non-null values query2.orderByFields = ["WORKSTATUS"]; // sort it so we won't have to later query2.returnGeometry = false; // turn geometry off, required to be false when using returnDistinctValues query2.returnDistinctValues = true; query2.outFields = ["WORKSTATUS"]; //Now use query results to find out the coded domain values for the layer field queryTask2.execute(query2, function(results){ var resultItems = []; var resultCount = results.features.length; var store3 = new Memory({data:[]}); dijit.byId("uniqueValuesSelect2").set('store',store3); var data = array.map(results.fields[0].domain.codedValues,lang.hitch(this,function(info,index){ var value = info.name; console.log(info); var dataItem = { id:index, name:value }; return dataItem; })); store3 = new Memory({data:data}); dijit.byId("uniqueValuesSelect2").set('store',store3); });
Once this was done, everything else was pretty easy. On the select-change event of the dropdown menu, the feature service would be queried for the relevant work ID and the query results pointed to the relevant HTML inputs for display as shown below:
//Capture the select - change event of the HTML select element on(dom.byId("workID"),"change",function (evt){ //Initialize query based on the selected value var selectQuery = new Query(); selectQuery.where = "WORKID = " + evt.target.value; teamsFL.selectFeatures(selectQuery, FeatureLayer.SELECTION_NEW, function(features) { if (features.length > 0) { //store the current feature updateFeature = features[0]; document.getElementById("uniqueValuesSelect").value = updateFeature.attributes.PROJTYPE; document.getElementById("uniqueValuesSelect2").value = updateFeature.attributes.WORKSTATUS; document.getElementById("CHARGECODE").value = updateFeature.attributes.CHARGECODE; document.getElementById("LOCATION").value = updateFeature.attributes.LOCATION; console.log(updateFeature.attributes.CHARGECODE); } else { } }); if(i == 0){ i++; //Add the Save button var saveButton = new Button({ label: "Save", "class": "saveButton"},domConstruct.create("div")); domConstruct.place(saveButton.domNode, "buttonious"); //Add the functionality of the save button saveButton.on("click", function() { updateFeature.attributes.PROJTYPE = document.getElementById("uniqueValuesSelect").value; updateFeature.attributes.WORKSTATUS = document.getElementById("uniqueValuesSelect2").value; updateFeature.attributes.CHARGECODE = document.getElementById("CHARGECODE").value; updateFeature.attributes.LOCATION = document.getElementById("LOCATION").value; updateFeature.getLayer().applyEdits(null, [updateFeature], null, function (adds, updates, deletes) { alert("Updated feature successfully, OBJECTID: " + updates[0].objectId); document.getElementById("CHARGECODE").value = ""; document.getElementById("LOCATION").value = ""; }, function (err) { //when an error occurs alert("Apply Edits Failed: " + err.message); }) }); }else{ console.log("already added attribute inspector"); } });
Saving the changes on the feature service layer followed the same pattern as before, the only difference being that this time, specifications were made as to which input value belonged to which feature attribute as shown below:
updateFeature.attributes.PROJTYPE = document.getElementById("uniqueValuesSelect").value; updateFeature.attributes.WORKSTATUS = document.getElementById("uniqueValuesSelect2").value; updateFeature.attributes.CHARGECODE = document.getElementById("CHARGECODE").value; updateFeature.attributes.LOCATION = document.getElementById("LOCATION").value;
That was pretty much it. Of course, the sample given here needs to be made more appealing (don't present such work to a client - dress it up with good formatting and CSS) but that was basically the guts of what our form solution entailed. I hope it was informative and helps someone some day.
Happy Coding!!!