AnsweredAssumed Answered

How to customize ESRI JavaScript Viewer template

Question asked by zhouleizhou on Oct 2, 2014
Latest reply on Oct 2, 2014 by zhouleizhou

We need to customize the ESRI’s JavaScript Template as the following from ESRI's Github: 


I insert our own codes in two files: one is index.html and the other is main.js inside the js folder. What we want to do is to create our own draw tool in a separate pane on the left (see the image below), and control it from main.js; in addition we want to display the information in the datagrid at the bottom when users use the draw tool to select features on the map.



I put the source codes of index.html and main.js as below.  In the viewer template, these are the only two files that we made modification.  The debug of main.js always indicated that “Cannnot read property ‘graphics’ of undefined”.  I post the question as the following before but still don’t understand where the map is loaded.


In main.js file, all the other codes are the same, our own customized codes are inserted all inside the addLayers: function (tool, toolbar, panelClass) {****}, this addLyers function is ESRI’s built-in function. Only this part is posted below:

_addLayers: function (tool, toolbar, panelClass) {
    //Toggle layer visibility if web map has operational layers 
    var deferred = new Deferred();

    var layers = this.config.response.itemInfo.itemData.operationalLayers;
    //alert("The layer lable is  " + layers[0].title)
    if (layers.length === 0) {
    } else {
        if (has("layers")) {

            //Set up the query function *****************************************
            //Build a feature layer 

            var j9t4 = new InfoTemplate("Current Land Use", "${*}");
            var sUrlQuakesLayer = "";
            var outFieldsQuakes = ["ParcelID", "Acres", "Current_Land_Use"];
             var lyrQuakes = new FeatureLayer(sUrlQuakesLayer, {
                id: "Current Land Use",
                outFields: outFieldsQuakes
            //Set up a single draw tool as Polygon for test purpose
            var tbDraw = new Draw(;
            tbDraw.on("draw-end", displayPolygon); 
            function displayPolygon(evt) {
                // Get the geometry from the event object
                var geometryInput = evt.geometry;
                // Define symbol for finished polygon
                var tbDrawSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, new SimpleLineSymbol(SimpleLineSymbol.STYLE_DASHDOT, new Color([255, 255, 0]), 2), new Color([255, 255, 0, 0.2]));
                // Clear the map's graphics layer
      ; // Debug always indicated that graphics is not defined
                //Step: Construct and add the polygon graphic
                var graphicPolygon = new Graphic(geometryInput, tbDrawSymbol);
      ; //Debug always indicated that graphics is not defined
                // Call the next function 
            } //displayPolygon ends here 

            //Create a serial of the draw tool buttons as point, freehandpolyline and freehandpolygon
  "load", initToolbar); // Debug indicated initToolbar can not be called
            var tb;
            function initToolbar(evt) {
                tb = new Draw(;
                tb.on("draw-end", addGraphic);
                // activate drawing tools on button click
                registry.byId("point").on("click", function () {
                    alert("You will start to use POINT drawing function");
                    tb.on("draw-end", addGraphic);//it can not be called
                registry.byId("freehandpolyline").on("click", function () {
                    alert("You will start to use POLYLINE drawing function");
                    tb.on("draw-end", addGraphic);//it can not be called
                registry.byId("freehandpolygon").on("click", function () {
                    alert("You will start to use POLYGON drawing function");
                    tb.on("draw-end", addGraphic);//it can not be called

                registry.byId("stop").on("click", function () {
                    alert("You have selected to STOP the drawing function");
            function addGraphic(evt) {
                //create a random color for the symbols
                var r = Math.floor(Math.random() * 255);
                var g = Math.floor(Math.random() * 255);
                var b = Math.floor(Math.random() * 255);

                var geometryInput = evt.geometry;//copy from displayPolygon(evt)
                var type = evt.geometry.type;
                var symbol;

                if (type === "point" || type === "multipoint") {

                    symbol = new SimpleMarkerSymbol(
                      20, new SimpleLineSymbol(
                        new Color([r, g, b, 0.5]),
                      new Color([r, g, b, 0.9]));
                } else if (type === "line" || type === "polyline") {
                    var symbol = new SimpleLineSymbol(
                      new Color([r, g, b, 0.85]),
                    ); //selectQuakes(geometryInput);
                } else {

                    symbol = new SimpleFillSymbol(
                      new SimpleLineSymbol(
                        new Color([r, g, b, 0.9]),
                      ), new Color([r, g, b, 0.5]));

                } // else Ends here
                var graphic = new Graphic(evt.geometry, symbol);
                selectQuakes(geometryInput); //goes to the next function to call
            //SelectQuakes set up
            function selectQuakes(geometryInput) {
                alert("Going into selectQuakes--2"); //------------------------
                // Define symbol for selected features (using JSON syntax for improved readability!)
                var symbolSelected = new SimpleMarkerSymbol({
                    "type": "esriSMS",
                    "style": "esriSMSCircle",
                    "color": [100, 100, 100, 128],
                    "size": 6,
                        "color": [255, 0, 0, 214],
                        "width": 1

                var sls = new SimpleLineSymbol({
                    "type": "esriSLS",
                    "style": "esriSLSSolid",
                    "color": [67, 0, 255, 40],
                    "width": 5


                var sfs = new SimpleFillSymbol({
                    "type": "esriSFS",
                    "style": "esriSFSSolid",
                    "color": [255, 255, 0, 200],
                    "outline": {
                        "type": "esriSLS",
                        "style": "esriSLSSolid",
                        "color": [255, 0, 0, 215],
                        "width": 2

                }); //LAST NUMBER AS A ALPHA VALUE


                 * Step: Initialize the query
                var queryQuakes = new Query();
                queryQuakes.geometry = geometryInput;

                lyrQuakes.on("selection-complete", populateGrid);
                lyrQuakes.selectFeatures(queryQuakes, FeatureLayer.SELECTION_NEW);
            } // selectQuakes () ends here

            //Create a datagrid 
            var gridQuakes = new (declare([Grid, Selection]))({
                bufferRows: Infinity,
                columns: {
                    ParcelID: "Parcel ID",
                    Acres: "Acres",
                    Current_Land_Use: "Current Land Use",
            }, "divGrid2"); 
            //Pop up to index div compoment 
            function populateGrid(results) {

                var gridData;
                dataQuakes =, function (feature) {
                    var dateConvert = new Date(feature.attributes[outFieldsQuakes[2]]).toLocaleString();
                    return {
                         * Step: Reference the attribute field values
                        "ParcelID": feature.attributes[outFieldsQuakes[0]],
                        "Acres": feature.attributes[outFieldsQuakes[1]],
                        "Current_Land_Use": feature.attributes[outFieldsQuakes[2]],
                // Pass the data to the grid
                var memStore = new Memory({
                    data: dataQuakes
                gridQuakes.set("store", memStore);
            }   //populateGrid fucntion ends here

            //Use small panel class if layer layer is less than 5
            if (layers.length < 5) {
                panelClass = "small";
            } else if (layers.length < 15) {
                panelClass = "medium";
            } else {
                panelClass = "large";
            var layersDiv = toolbar.createTool(tool, panelClass);

            var toc = new TableOfContents({
                layers: layers
            }, domConstruct.create("div", {}, layersDiv));

        } else {
    return deferred.promise; 
}, //999999999999999999999999999999999999999999999999999999999999999999999



Index.html source codes below:


            This pane is for seleciton layers only                        

                    Please Select the Buttons Below to Activate the Drawing Tools                


                Click "Stop Drawing" Button to Disable Drawing Tools;                
After Doing this, only Click-Pop-Up Function is Available            



The other question is that the inserted codes in index.html seem very weird, e.g., <button id="point"…> and <button id="freehandpolyline"…>, <button id="freehandpolygon"…> do not display well.  The TabContainer with two ContenPanes as divGrid and divGrid2, does not show the two Tabs in a row. 


Thanks a lot for reading this and any hint will be very helpful!