Saturday, June 9, 2012

ARCGIS JavaScript API – BASIC EDITING COMMANDS SECTION 2 – PART V

1.     Introduction

Until now we saw how we can create and update geometries  (points, polylines and polygones) using the edit and draw widgets. Using the save button we transfer the modification to the ArcGIS server which in turn updates the SDE database. Also important is the data entry of attribute data of a feature. I will illustrate how we can use the attribute template widget to create a general attribute editor for features.
The navigation within the tab control and the accordion control inside a tab will be done with the help of custom bindings as defined in the knockoutJS framework. As we illustrated in previous commands, the handling of the GUI components will be kept out of the ArcGIS framework.
2.     Attribute edit

To simplify the attribute editing we can use the attribute inspector of the ArcGIS JavaScript API. This is a dojo widget that covers the full editing of attributes for a feature. Depending on the attribute field type different input editors are activated in the Dojo component.
The attribute inspector is encapsulated in some general edit attribute method added into the GisEditing class.  The only parameter needed for the tool is the list of fields that needs to be updated. In the implementation a general editing application, we called this method with a null value as field list. Using a null value as field list results in adding all attribute fields of the feature. The object ID is always masked out by the attribute inspector. and does not appears on the input form.

editAttributes: function (fieldInfos) {
 try {
  if (currentFeatureLayer == null)
       return;
   currentOperation = "EditAttributes";
   if (fieldInfos == null)
       fieldInfos = [];
   var layerInfos = [{
      'featureLayer': GisOperation.getMap().getLayer(currentFeatureLayer.name),
      'showDeleteButton': false,
      'isEditable': true,
      'fieldInfos': fieldInfos
   }];
   if (attributeInspector == null) {
      var contentHolder = "<div id='" + attributesDiv + "'></div>";
      require(["dojo/dom-construct"], function (domConstruct) {
         domConstruct.place(contentHolder, "attributeDetails", "first");
      });
      attributeInspector = new esri.dijit.AttributeInspector({
        layerInfos: layerInfos
        }, attributesDiv);
      dojo.connect(attributeInspector, "onAttributeChange", function (feature, fieldName,  
          newFieldValue) {
        //store the updates to apply when the save button is clicked
        currentFeatureLayer.getSelectedFeatures()[0].attributes[fieldName] = newFieldValue;
     });
     }
   this.selectFeatures();
 } catch (err) {
     logging.logMessage("E", "editAttributes failed -->" + err.message, "gisEditing");
 }
},

To  include the attribute inspector widget into the web page,  the best implementation I found is using the dom contructor of the dojo library.  I found out that this is the most stable creation of this component into the web page. This result of the display within the tabular control looks like this:
The nice thing is that with the attribute inspector widget , you get a rich input controls which handles the different input data types of the feature.  The ‘onAttributeChange’ event of the attribute inspector is responsible for the update of the modified attributes into the selected feature. The attribute inspector add also support for the usage of attachments. As you can also see, the attribute inspector add multi language support., but as I did with Silverlight I did not add some multi language support. 
3.     Move point

Although we add a separate tool button to move a point, the implementation of the tool is exactly the same as modifying the vertices of a polygon or polyline. In the main view model class the implementation of the edit tools looks like this :
Edit of the vertices:
    this.editExecute = function () {
        editToolbarGeneralViewModel.editCommand(setEditActive);
    };

 Move of a point:
    this.movePointExecute = function () {
        editToolbarGeneralViewModel.editCommand(setEditActive);
    };

 The underlying edit command will handle the different feature types, and in case of a map point you are allow the move of the point with a drag operation.
4.     Save feature

The save action has been split into the three different actions that can be done on a feature layer,  namely create, update and delete. The code below shows that with the current API you can have the full control over editing on feature layers and how the results are save at the ArcGIS server.

saveAll: function () {
  try {
      var updateGraphic;
      if (currentOperation == "EditVertices") {
         var graphicNew = editTool.getCurrentState();
         if (graphicNew.isModified) {
             updateGraphic = currentFeatureLayer.getSelectedFeatures()[0].setGeometry(graphicNew.graphic.geometry);
             currentFeatureLayer.applyEdits(null, [updateGraphic], null, function (addResults, updateResults, deleteResults) {
             var updateCount = updateResults.length;
             }, function (err) {
                 logging.logMessage("E", "saveAll applyEdits failed -->" + err.message, "gisEditing");
             });
         }
         editTool.deactivate();
      }
      else if (currentOperation == "EditAttributes") {
        try {
          attributeInspector.destroy();
          attributeInspector = null;
          updateGraphic = currentFeatureLayer.getSelectedFeatures()[0];
          currentFeatureLayer.applyEdits(null, [updateGraphic], null, function (addResults, updateResults, deleteResults) {
              var updateCount = updateResults.length;
          }, function (err) {
              logging.logMessage("E", "saveAll applyEdits failed -->" + err.message, "gisEditing");
          });
        } catch (err) {
            logging.logMessage("E", "saveAll failed EditAttributes-->" + err.message, "gisEditing");
        }
      }
      else if (currentOperation == "CreateFeature") {
        if (currentGeometry != null) {
           var symbol;
          if (currentFeatureLayer.geometryType == "esriGeometryPolygon") {
               symbol = gisOperation.getSelectionFillSymbol();
          }
          else if (currentFeatureLayer.geometryType == "esriGeometryPolyline") {
               symbol = gisOperation.getSelectionLineSymbol();
          }
          else if (currentFeatureLayer.geometryType == "esriGeometryPoint") {
               symbol = gisOperation.getSelectionMarkerSymbol();
          }
          var addGraphic = new esri.Graphic(currentGeometry, symbol, currentAttributes);
          currentFeatureLayer.applyEdits([addGraphic], null, null, function (addResults, updateResults, deleteResults) {
              var addCount = addResults.length;
              }, function (err) {
                 logging.logMessage("E", "saveAll apply add failed -->" + err.message, "gisEditing");
           });
        }
        gisOperation.getDraw().deactivate();
      }
      else if (currentOperation == "DeleteFeatures") {
        try {
         var deleteFeatures = new Array();
         require(["dojo/_base/array"], function (array) {
           array.forEach(currentFeatureLayer.getSelectedFeatures(), function (feature, ind) {
              deleteFeatures.push(feature);
           });
         });
         currentFeatureLayer.applyEdits(null, null, deleteFeatures, function (addResults, updateResults, deleteResults) {
            var deleteCount = deleteResults.length;
            }, function (err) {
              logging.logMessage("E", "saveAll applyEdits failed -->" + err.message, "gisEditing");
          });
        } catch (err) {
          logging.logMessage("E", "saveAll failed DeleteFeatures -->" + err.message, "gisEditing");
        }
      }
      currentOperation = "";
      currentAttributes = new Array();
      this.clearSelectFeatures();
      gisOperation.getSelectLayer().clear();
   } catch (err) {
       logging.logMessage("E", "saveAll failed -->" + err.message, "gisEditing")
 }
},


In the save there is a lot of asynchronous processing. By hiding this asynchronous functionality, it makes the job easier at the GUI development. It is also important to add extensive error handling to have a trace in case of errors occurred during the save operation.
5.     Undo modifications
As long as you did not a save with the save button, nothing is modified on the ArcGIS server. Simply clear the graphic layer, as it holds the modification or creation. In case of attribute update, destroy the attribute inspector.

6.     Summary

In the edit tools I showed you how you can implement some simple basis editing of feature layers. Editing, updating or delete of feature can be performed in the same way that is done with ArcGIS Desktop. With the attribute inspector you even get a powerful attribute editor. In the future I hope to illustrate how you can create more complex edit tools as already illustrated in the Silverlight ArcGIS framework illustrated in previous documents. The basic idea will be creating basic building blocks of editing tools that can be put together to create more complex edit tools. This approach is not special, probably a lot of you has already built ArcMap extensions with the main purpose to create extended edit tools to simplify the job of GIS editors.
Based on my experience of writing ArcMap extension for enhanced GIS editing, I will later illustrate how some of this more complex editing tools I implemented in the past as ArcMap tools or commands can be written as tools or commands in JavaScript as part of an ArcGIS Application framework.
ESRI inc. did a real good job by putting an ArcGIS API framework in place to encapsulate the REST services for the ArcGIS Server together with the 10.01 editing functionality for feature layers. This gives us as GIS developers an

3 comments:

  1. Thank Johnny Penet,
    This article is very helpful. It saved me a lot of time. Is there any demo source code?

    ReplyDelete
  2. In the .jpg you show, how is the attribute detail area being formatted. Specifically, you show a section bijlagen. Any help there?

    Thanks,

    ReplyDelete
  3. i would like to save my edits directly into databse.

    can we do that??

    thanks in advance

    ReplyDelete