Search code examples
javascriptdojoesriarcgis-js-apiarcgis-runtime

ARCGIS Attribute Editing at RunTime Using Javascript API


Currently I am building a web Application using ArcGIS Javascript API.

Where I can add marker to the map graphics, on adding marker request I am setting few attributes to that marker using Popup Template like this

map.graphics.add(new Graphic(evt.geometry, symbol, PointAtt, popupTemplate));

Here I want to ask, how I can edit these attributes at Map Runtime because I want to do some changes in the attributes.

<script src="https://js.arcgis.com/3.17/"></script>
    <script>
      var map, tb;
      var otherWindow;
      var PointAtt = {};
      require([
            "esri/map",
            "esri/toolbars/draw",
            "esri/dijit/PopupTemplate",
            "esri/symbols/SimpleMarkerSymbol", "esri/symbols/SimpleLineSymbol",
            "esri/symbols/PictureFillSymbol", "esri/symbols/CartographicLineSymbol",
            "esri/graphic",
            "esri/Color", "dojo/dom", "dojo/on",
            "dojo/domReady!"
        ], function (
            Map, Draw, PopupTemplate,
            SimpleMarkerSymbol, SimpleLineSymbol,
            PictureFillSymbol, CartographicLineSymbol,
            Graphic,
            Color, dom, on) {
        map = new Map("mapDiv", {
                basemap : "streets",
                center : [-25.312, 34.307],
                zoom : 3
            });

        otherWindow = window.open("integrationPage.html", "otherWindow");
        map.on("load", initToolbar);

        // markerSymbol is used for point and multipoint, see http://raphaeljs.com/icons/#talkq for more examples
        var markerSymbol = new SimpleMarkerSymbol();
        markerSymbol.setPath("M16,4.938c-7.732,0-14,4.701-14,10.5c0,1.981,0.741,3.833,2.016,5.414L2,25.272l5.613-1.44c2.339,1.316,5.237,2.106,8.387,2.106c7.732,0,14-4.701,14-10.5S23.732,4.938,16,4.938zM16.868,21.375h-1.969v-1.889h1.969V21.375zM16.772,18.094h-1.777l-0.176-8.083h2.113L16.772,18.094z");
        markerSymbol.setColor(new Color("#00FFFF"));

        // lineSymbol used for freehand polyline, polyline and line.
        var lineSymbol = new CartographicLineSymbol(
                CartographicLineSymbol.STYLE_SOLID,
                new Color([255, 0, 0]), 10,
                CartographicLineSymbol.CAP_ROUND,
                CartographicLineSymbol.JOIN_MITER, 5);

        // fill symbol used for extent, polygon and freehand polygon, use a picture fill symbol
        // the images folder contains additional fill images, other options: sand.png, swamp.png or stiple.png
        var fillSymbol = new PictureFillSymbol(
                "images/mangrove.png",
                new SimpleLineSymbol(
                    SimpleLineSymbol.STYLE_SOLID,
                    new Color('#000'),
                    1),
                42,
                42);

        function initToolbar() {
            tb = new Draw(map);
            tb.on("draw-end", addGraphic);
            // Get Marker Click Event
            map.graphics.on("click", function (evt) {
                // alert("Marker Clicked");
                var lat = evt.mapPoint.getLatitude();
                var lon = evt.mapPoint.getLongitude();


                var sendEvent = [];
                sendEvent[0] = evt.graphic.attributes.ID;
                sendEvent[1] = evt.mapPoint.getLatitude();
                sendEvent[2] = evt.mapPoint.getLongitude();
                // Sending event to other html page
                otherWindow.postMessage(sendEvent, "http://localhost:9090");


            });
            // event delegation so a click handler is not
            // needed for each individual button
            on(dom.byId("info"), "click", function (evt) {
                if (evt.target.id === "info") {
                    return;
                }
                var tool = evt.target.id.toLowerCase();
                map.disableMapNavigation();
                tb.activate(tool);
            });
        }

        function addGraphic(evt) {
            // deactivate the toolbar and clear existing graphics
            tb.deactivate();
            map.enableMapNavigation();

            var sendEvent = []; // Array which is sent to other sources
            var counter = 0;
            sendEvent[0] = "added"
            sendEvent[1] = evt.geometry.getLatitude();
            sendEvent[2] = evt.geometry.getLongitude();


            otherWindow.postMessage(sendEvent, "http://localhost:9090");

            // Marker ID is being received from the Key Generator
            window.addEventListener("message", function (event) {
                var receivedEvent;
                console.log("onMessage::" + event.data);
                receivedEvent = event.data;

                if (receivedEvent[0] == "added" && counter == 0) {
                    PointAtt = {
                        Name : "Islamabad", // The name of the pipeline
                        Type : "City", // The owner of the pipeline
                        ID : receivedEvent[1],// The length of the pipeline
                        Latitude : evt.geometry.getLatitude(),
                        Longitude: evt.geometry.getLongitude()
                    };
                    var popupTemplate = new PopupTemplate({
                            title : "{*}", // The title of the popup will be the name of the pipeline
                            content : "{*}" // Displays a table of all the attributes in the popup
                        })

                        // figure out which symbol to use
                        var symbol;
                    if (evt.geometry.type === "point" || evt.geometry.type === "multipoint") {
                        symbol = markerSymbol;
                    } else if (evt.geometry.type === "line" || evt.geometry.type === "polyline") {
                        symbol = lineSymbol;
                    } else {
                        symbol = fillSymbol;
                    }
                    map.graphics.add(new Graphic(evt.geometry, symbol, PointAtt, popupTemplate));
                    counter = counter + 1;
                    event.data = "";
                }

            }, false);

        }
      });

Solution

  • you can use esri AttributeInspector for this. Though it works for feature layers to but you can customize it accordingly.

    Either you can create feature layer on the map and add graphics to it and pass that to layerInfos OR you can override the attribute inspector so support graphics layer too.

    Use Below code for this-

     //add a save button next to the delete button
          var saveButton = new Button({ label: "Save", "class": "saveButton"},domConstruct.create("div"));
          domConstruct.place(saveButton.domNode, attInspector.deleteBtn.domNode, "after");
    
          saveButton.on("click", function() {
            updateFeature.getLayer().applyEdits(null, [updateFeature], null);
          });
    
          attInspector.on("attribute-change", function(evt) {
            //store the updates to apply when the save button is clicked
            updateFeature.attributes[evt.fieldName] = evt.fieldValue;
          });
    
          attInspector.on("next", function(evt) {
            updateFeature = evt.feature;
            console.log("Next " + updateFeature.attributes.OBJECTID);
          });
    

    For attribute inspector please click here...

    Here is the working code for feature layer-

    <!DOCTYPE html>
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
    <title>Editable FeatureLayer with Attribute Inspector</title>
    
    <link rel="stylesheet" href="https://js.arcgis.com/3.18/dijit/themes/claro/claro.css">
    <link rel="stylesheet" href="https://js.arcgis.com/3.18/esri/css/esri.css">
    <style>
      html, body, #mapDiv{
        height: 100%;
        width: 100%;
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
      #detailPane{
        padding: 6px;
        height:20px;
        color:#570026;
        font-size:12pt;
        font-weight:600;
        overflow: hidden;
      }
      .dj_ie .infowindow .window .top .right .user .content { position: relative; }
      .dj_ie .simpleInfoWindow .content {position: relative;}
    
      .esriAttributeInspector .atiLayerName {display:none;}
    </style>
    
    <script src="https://js.arcgis.com/3.18/"></script>
    <script>
      var map, updateFeature;
    
      require([
        "esri/map",
        "esri/layers/FeatureLayer",
        "esri/dijit/AttributeInspector",
    
        "esri/symbols/SimpleLineSymbol",
        "esri/symbols/SimpleMarkerSymbol",
        "esri/Color",
        "esri/renderers/UniqueValueRenderer",
    
        "esri/config",
    
        "esri/tasks/query",
        "dojo/dom-construct",
        "dijit/form/Button",
    
        "dojo/domReady!"
      ], function(
        Map, FeatureLayer, AttributeInspector,
        SimpleLineSymbol, SimpleMarkerSymbol, Color, UniqueValueRenderer,
        esriConfig,
        Query, domConstruct, Button
      ) {
        // refer to "Using the Proxy Page" for more information:  https://developers.arcgis.com/javascript/3/jshelp/ags_proxy.html
        esriConfig.defaults.io.proxyUrl = "/proxy/";
    
        map = new Map("mapDiv", {
          basemap: "dark-gray",
          center: [-97.395, 37.537],
          zoom: 5
        });
    
        map.on("layers-add-result", initSelectToolbar);
    
        //Feature Layer representing 2015 men's NCAA basketball tournament teams
        var teamsFL = new FeatureLayer("https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/NCAA_Tourney_2015/FeatureServer/1", {
          outFields: ["University", "WINPER", "Rd_64_Venue", "Rd_64_Result", "Rd_64_Margin"]
        });
    
        var selectionSymbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CIRCLE, 6,
            new SimpleLineSymbol(
                "solid",
                new Color([255,0,0,0.5]),
                4
            ),
            new Color("#ED3939")
        );
    
        var defaultSymbol = new SimpleMarkerSymbol(
            SimpleMarkerSymbol.STYLE_CIRCLE, 7,
            null,
            new Color([255,255,255])
        );
        teamsFL.setSelectionSymbol(selectionSymbol);
    
        //Symbolize features by W/L record
        var recordRenderer = new UniqueValueRenderer(defaultSymbol, "Rd_64_Result");
        recordRenderer.addValue("W", new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 7, null, new Color([93,240,79])));
        recordRenderer.addValue("L", new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CIRCLE, 7, null, new Color([240,146,79])));
        teamsFL.setRenderer(recordRenderer);
    
        map.addLayers([teamsFL]);
    
        function initSelectToolbar(evt) {
          var teamsFL = evt.layers[0].layer;
          var selectQuery = new Query();
    
          map.on("click", function(evt) {
            selectQuery.geometry = evt.mapPoint;
            selectQuery.distance = 50;
            selectQuery.units = "miles"
            selectQuery.returnGeometry = true;
            teamsFL.selectFeatures(selectQuery, FeatureLayer.SELECTION_NEW, function(features) {
              if (features.length > 0) {
                //store the current feature
                updateFeature = features[0];
                map.infoWindow.setTitle(features[0].getLayer().name);
                map.infoWindow.show(evt.screenPoint, map.getInfoWindowAnchor(evt.screenPoint));
              }
              else {
                map.infoWindow.hide();
              }
            });
          });
    
          map.infoWindow.on("hide", function() {
            teamsFL.clearSelection();
          });
    
          var layerInfos = [
            {
              'featureLayer': teamsFL,
              'showAttachments': false,
              'isEditable': true,
              'fieldInfos': [
                {'fieldName': 'University', 'isEditable': false, 'label': 'School:'},
                {'fieldName': 'WINPER', 'isEditable': true, 'tooltip': 'Win percentage', 'label': 'Win percentage:'},
                {'fieldName': 'Rd_64_Venue', 'isEditable': false, 'label': 'Rd 1 Venue:'},
                {'fieldName': 'Rd_64_Result', 'isEditable': true, 'tooltip': 'First round result (W/L)', 'label': 'Rd 1 Result:'},
                {'fieldName': 'Rd_64_Margin', 'isEditable': true, 'tooltip': 'First round margin of victory/loss', 'label': 'Rd 1 Margin:'}
              ]
            }
          ];
    
          //Initialize Attribute Inspector
          var attInspector = new AttributeInspector({
            layerInfos: layerInfos
          }, domConstruct.create("div"));
    
          //add a save button next to the delete button
          var saveButton = new Button({ label: "Save", "class": "saveButton"},domConstruct.create("div"));
          domConstruct.place(saveButton.domNode, attInspector.deleteBtn.domNode, "after");
    
          saveButton.on("click", function() {
            updateFeature.getLayer().applyEdits(null, [updateFeature], null);
          });
    
          attInspector.on("attribute-change", function(evt) {
            //store the updates to apply when the save button is clicked
            updateFeature.attributes[evt.fieldName] = evt.fieldValue;
          });
    
          attInspector.on("next", function(evt) {
            updateFeature = evt.feature;
            console.log("Next " + updateFeature.attributes.OBJECTID);
          });
    
          attInspector.on("delete", function(evt) {
            evt.feature.getLayer().applyEdits(null, null, [evt.feature]);
            map.infoWindow.hide();
          });
    
          map.infoWindow.setContent(attInspector.domNode);
          map.infoWindow.resize(350, 240);
        }
      });
    </script>
    </head>
    
    <body class="claro">
      <div id="detailPane">
        Click to display the attribute inspector for all NCAA men's basketball tournament teams within 50 miles of click.
      </div>
      <div id="mapDiv"></div>
    </body>
    </html>

    Output:-

    enter image description here