Select to view content in your preferred language

dGrid, sorting Memory vs. sorting Grid

6112
5
Jump to solution
07-02-2014 01:46 PM
TracySchloss
Honored Contributor
I have a grid I'm creating that needed to be sorted, and also be able to save the grid to a CSV file and retain the sort I have on the grid.  The grid is created  in the results handler of queryTask.  At this point, I simply run sort on the field I want and the grid looks fine.  But that's a sort on the grid, not on the underlying data.

  grid = new (declare([Grid, ColumnHider, DijitRegistry, ColumnResizer]))({             id:"myGrid',              columns: gridcolumns,             store: currentMemory         });         grid.startup();         grid.sort('NAME');


Next I have a button that will allow the user to save this information to a CSV.  It's getting created into the same container the grid is, so I can pass the argument of the grid name to it. 

        var saveButton = new Button({         label: "Save List",         onClick: function(){        saveGridCSV(grid);         }     }, "btnSave");      registry.byId("gridContainer").addChild(saveButton);       registry.byId("gridContainer").addChild(grid); 


Within my saveGridCSV, I'm going back to the store of the grid and using it to get the values formatted for the CSV. 
//functions for saving to Excel   function saveGridCSV(gridData){     var fName;      if (gridData) {       var gridLength = gridData.store.data.length;       dataArray.length = 0;        fieldNames.length = 0;       var fieldValue = "";          var gridColumns = gridData.columns;       var fieldHeaders = ["ID", "County", "Acres Treated", "Pct Area Treated", "Pct Change 2002-2007"];       for (var col in gridColumns) {        fieldNames.push(col);       }   var lastCol = fieldNames.length -1;   var lastField = fieldNames[lastCol];   dataArray.push(fieldHeaders.toString()+ " \n");  //  dataArray.push(fieldNames.toString()+ " \n");       var gridStore = gridData.store;     //steps through each record, pushes the values into an array that is formatted for CSV compatibility         for (var i = 0; i < gridLength; i++) {             var gridRow = gridStore.data;             arrayUtils.forEach(fieldNames, function(fieldName){                 fieldValue = gridRow[fieldName];                 var stringValue = String(fieldValue);                 if (stringValue.indexOf(",") > 0) { //removes any commas from data                                         stringValue = stringValue.replace(/,/g, " ");                 }                 if (stringValue.indexOf('\'') != -1 || stringValue.indexOf('\"') != -1) { //removes any slashes from data                     //  console.log ("Data has a slash in it. Not sure of this section of the code!");                     if (stringValue.indexOf('\"') != -1) {                         stringValue = stringValue.replace("\"", "\"\"");                     }                     stringValue = "\"" + stringValue + "\"";                 }                 if (fieldName == lastField) {                     dataArray.push(stringValue + " \n");//adds a new line when value is from the last field                 } else {                     dataArray.push(stringValue);//otherwise just adds the value                 }             });         }//one row pushed to array              var data = dataArray.join();         var inputData = data.replace(/\n,/g, "\n");//some clean up to get rid of the leading commas in the data               submitCSVprint(gridData.id, inputData);     } else {  //nothing to save        alert ("Error saving data.");     }   }


This is working well, except that I still want the data sorted on my NAME field and now it's not.  The sorting I performed early was on the grid, not on the underlying Memory.

My question is, how do I sort the Memory instead so the CSV output matches what the user sees in the grid?
0 Kudos
1 Solution

Accepted Solutions
KenBuja
MVP Esteemed Contributor
This is a roundabout way of doing it, but it seems to work properly. This is using the dGrid sample, now sorted on the median net worth. The section in red is the new stuff.

<!DOCTYPE html> <html> <head>     <meta charset="utf-8">     <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">     <title>Map with a Dojo dGrid</title>      <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dojo/resources/dojo.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dgrid/css/dgrid.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dgrid/css/skins/tundra.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dijit/themes/tundra/tundra.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/esri/css/esri.css">     <style>         html, body {             height: 100%;             width: 100%;             margin: 0;             padding: 0;             overflow: hidden;         }          #container {             height: 100%;             visibility: hidden;         }          #bottomPane {             height: 200px;         }          #grid {             height: 100%;         }          .dgrid {             border: none;         }          .field-id {             cursor: pointer;         }     </style>      <script src="http://js.arcgis.com/3.9/"></script>     <script>         // load dgrid, esri and dojo modules         // create the grid and the map         // then parse the dijit layout dijits         require([           "dojo/ready",           "dgrid/OnDemandGrid",           "dgrid/Selection",           "dojo/store/Memory",           "dojo/_base/array",           "dojo/dom-style",           "dijit/registry",           "esri/map",           "esri/layers/FeatureLayer",           "esri/symbols/SimpleFillSymbol",           "esri/tasks/QueryTask",           "esri/tasks/query",           "dojo/_base/declare",           "dojo/number",           "dojo/on",           "dojo/parser",           "dijit/layout/BorderContainer",           "dijit/layout/ContentPane"         ], function (             ready,             Grid,             Selection,             Memory,             array,             domStyle,             registry,             Map,             FeatureLayer,             SimpleFillSymbol,             QueryTask,             Query,             declare,             dojoNum,             on,             parser           ) {             ready(function () {                  parser.parse();                  // create the dgrid                 window.grid = new (declare([Grid, Selection]))({                     // use Infinity so that all data is available in the grid                     bufferRows: Infinity,                     columns: {                         "id": "ID",                         "stateName": "State Name",                         "median": { "label": "Median Net Worth", "formatter": dojoNum.format },                         "over1m": { "label": "Households Net Worth > $1M", "formatter": dojoNum.format }                     }                 }, "grid");                 // add a click listener on the ID column                 grid.on(".field-id:click", selectState);                  window.map = new Map("map", {                     basemap: "gray",                     center: [-101.426, 42.972],                     zoom: 4                 });                  window.statesUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Net_Worth/MapServer/4";                 window.outFields = ["OBJECTID", "NAME", "MEDNW_CY"];                  var fl = new FeatureLayer(window.statesUrl, {                     id: "states",                     mode: 1, // ONDEMAND, could also use FeatureLayer.MODE_ONDEMAND                     outFields: window.outFields                 });                  fl.on("load", function () {                     fl.maxScale = 0; // show the states layer at all scales                     fl.setSelectionSymbol(new SimpleFillSymbol().setOutline(null).setColor("#AEC7E3"));                 });                  fl.on("click", selectGrid);                  // change cursor to indicate features are click-able                 fl.on("mouse-over", function () {                     map.setMapCursor("pointer");                 });                 fl.on("mouse-out", function () {                     map.setMapCursor("default");                 });                  map.addLayer(fl);                  map.on("load", function (evt) {                     // show the border container now that the dijits                     // are rendered and the map has loaded                     domStyle.set(registry.byId("container").domNode, "visibility", "visible");                     populateGrid(Memory); // pass a reference to the MemoryStore constructor                 });                  function populateGrid(Memory) {                     var qt = new QueryTask(window.statesUrl);                     var query = new Query();                     query.where = "1=1";                     query.returnGeometry = false;                     query.outFields = window.outFields;                     qt.execute(query, function (results) {                         var data = array.map(results.features, function (feature) {                             return {                                 // property names used here match those used when creating the dgrid                                 "id": feature.attributes[window.outFields[0]],                                 "stateName": feature.attributes[window.outFields[1]],                                 "median": feature.attributes[window.outFields[2]],                                 "over1m": feature.attributes[window.outFields[3]]                             }                         });                           var memStore = new Memory({ data: data });                         var object = memStore.query(function (item) {                             return item;                         }, { sort: [{ attribute: "median", descending: "true" }] });                         var newStore = new Memory({ data: object });                     window.grid.set("store", newStore);                 });             }                 // fires when a row in the dgrid is clicked             function selectState(e) {                 // select the feature                 var fl = map.getLayer("states");                 var query = new Query();                 query.objectIds = [parseInt(e.target.innerHTML)];                 fl.selectFeatures(query, FeatureLayer.SELECTION_NEW, function (result) {                     if (result.length) {                         // re-center the map to the selected feature                         window.map.centerAt(result[0].geometry.getExtent().getCenter());                     } else {                         console.log("Feature Layer query returned no features... ", result);                     }                 });             }              // fires when a feature on the map is clicked             function selectGrid(e) {                 var id = e.graphic.attributes.OBJECTID;                 // select the feature that was clicked                 var query = new Query();                 query.objectIds = [id];                 var states = map.getLayer("states");                 states.selectFeatures(query, FeatureLayer.SELECTION_NEW);                 // select the corresponding row in the grid                 // and make sure it is in view                 grid.clearSelection();                 grid.select(id);                 grid.row(id).element.scrollIntoView();             }         }           );         });     </script> </head>  <body class="tundra">     <div id="container" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design: 'headline', gutters: false">         <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'center'"></div>         <div id="bottomPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'">             <div id="grid"></div>         </div>     </div> </body> </html> 

View solution in original post

0 Kudos
5 Replies
KenBuja
MVP Esteemed Contributor
Have you tried running a query on the Memory? The query has a sort option and this tutorial has a simple example of that.
0 Kudos
TracySchloss
Honored Contributor
I hadn't thought of that.  I feel like the documentation for dGrid and store is scattered all over various sites.  I wasn't sure what I should put in my query since I want all records.  Since I make a store for the initial grid creation, I thought sorting it before I put it in the grid in the first place seemed like a good idea.  Then when I pull the store again to make my CSV, it will already be sorted. 
   var featureAttributes = arrayUtils.map(results.featureSet.features, function(feature){     
      return feature.attributes;
   });
    var currentMemory = new Memory ({data:featureAttributes, idProperty:'OBJECTID'}); 
    currentMemory.query({NAME:"*"}, {
      sort: [{attribute: "NAME"},
       descending: false]
     });


This didn't give any errors, but it didn't sort my data either.  I threw in the descending argument, I'm not sure if that's the default already or not.
0 Kudos
KenBuja
MVP Esteemed Contributor
This is a roundabout way of doing it, but it seems to work properly. This is using the dGrid sample, now sorted on the median net worth. The section in red is the new stuff.

<!DOCTYPE html> <html> <head>     <meta charset="utf-8">     <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">     <title>Map with a Dojo dGrid</title>      <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dojo/resources/dojo.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dgrid/css/dgrid.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dgrid/css/skins/tundra.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/dojo/dijit/themes/tundra/tundra.css">     <link rel="stylesheet" href="http://js.arcgis.com/3.9/js/esri/css/esri.css">     <style>         html, body {             height: 100%;             width: 100%;             margin: 0;             padding: 0;             overflow: hidden;         }          #container {             height: 100%;             visibility: hidden;         }          #bottomPane {             height: 200px;         }          #grid {             height: 100%;         }          .dgrid {             border: none;         }          .field-id {             cursor: pointer;         }     </style>      <script src="http://js.arcgis.com/3.9/"></script>     <script>         // load dgrid, esri and dojo modules         // create the grid and the map         // then parse the dijit layout dijits         require([           "dojo/ready",           "dgrid/OnDemandGrid",           "dgrid/Selection",           "dojo/store/Memory",           "dojo/_base/array",           "dojo/dom-style",           "dijit/registry",           "esri/map",           "esri/layers/FeatureLayer",           "esri/symbols/SimpleFillSymbol",           "esri/tasks/QueryTask",           "esri/tasks/query",           "dojo/_base/declare",           "dojo/number",           "dojo/on",           "dojo/parser",           "dijit/layout/BorderContainer",           "dijit/layout/ContentPane"         ], function (             ready,             Grid,             Selection,             Memory,             array,             domStyle,             registry,             Map,             FeatureLayer,             SimpleFillSymbol,             QueryTask,             Query,             declare,             dojoNum,             on,             parser           ) {             ready(function () {                  parser.parse();                  // create the dgrid                 window.grid = new (declare([Grid, Selection]))({                     // use Infinity so that all data is available in the grid                     bufferRows: Infinity,                     columns: {                         "id": "ID",                         "stateName": "State Name",                         "median": { "label": "Median Net Worth", "formatter": dojoNum.format },                         "over1m": { "label": "Households Net Worth > $1M", "formatter": dojoNum.format }                     }                 }, "grid");                 // add a click listener on the ID column                 grid.on(".field-id:click", selectState);                  window.map = new Map("map", {                     basemap: "gray",                     center: [-101.426, 42.972],                     zoom: 4                 });                  window.statesUrl = "http://server.arcgisonline.com/ArcGIS/rest/services/Demographics/USA_Median_Net_Worth/MapServer/4";                 window.outFields = ["OBJECTID", "NAME", "MEDNW_CY"];                  var fl = new FeatureLayer(window.statesUrl, {                     id: "states",                     mode: 1, // ONDEMAND, could also use FeatureLayer.MODE_ONDEMAND                     outFields: window.outFields                 });                  fl.on("load", function () {                     fl.maxScale = 0; // show the states layer at all scales                     fl.setSelectionSymbol(new SimpleFillSymbol().setOutline(null).setColor("#AEC7E3"));                 });                  fl.on("click", selectGrid);                  // change cursor to indicate features are click-able                 fl.on("mouse-over", function () {                     map.setMapCursor("pointer");                 });                 fl.on("mouse-out", function () {                     map.setMapCursor("default");                 });                  map.addLayer(fl);                  map.on("load", function (evt) {                     // show the border container now that the dijits                     // are rendered and the map has loaded                     domStyle.set(registry.byId("container").domNode, "visibility", "visible");                     populateGrid(Memory); // pass a reference to the MemoryStore constructor                 });                  function populateGrid(Memory) {                     var qt = new QueryTask(window.statesUrl);                     var query = new Query();                     query.where = "1=1";                     query.returnGeometry = false;                     query.outFields = window.outFields;                     qt.execute(query, function (results) {                         var data = array.map(results.features, function (feature) {                             return {                                 // property names used here match those used when creating the dgrid                                 "id": feature.attributes[window.outFields[0]],                                 "stateName": feature.attributes[window.outFields[1]],                                 "median": feature.attributes[window.outFields[2]],                                 "over1m": feature.attributes[window.outFields[3]]                             }                         });                           var memStore = new Memory({ data: data });                         var object = memStore.query(function (item) {                             return item;                         }, { sort: [{ attribute: "median", descending: "true" }] });                         var newStore = new Memory({ data: object });                     window.grid.set("store", newStore);                 });             }                 // fires when a row in the dgrid is clicked             function selectState(e) {                 // select the feature                 var fl = map.getLayer("states");                 var query = new Query();                 query.objectIds = [parseInt(e.target.innerHTML)];                 fl.selectFeatures(query, FeatureLayer.SELECTION_NEW, function (result) {                     if (result.length) {                         // re-center the map to the selected feature                         window.map.centerAt(result[0].geometry.getExtent().getCenter());                     } else {                         console.log("Feature Layer query returned no features... ", result);                     }                 });             }              // fires when a feature on the map is clicked             function selectGrid(e) {                 var id = e.graphic.attributes.OBJECTID;                 // select the feature that was clicked                 var query = new Query();                 query.objectIds = [id];                 var states = map.getLayer("states");                 states.selectFeatures(query, FeatureLayer.SELECTION_NEW);                 // select the corresponding row in the grid                 // and make sure it is in view                 grid.clearSelection();                 grid.select(id);                 grid.row(id).element.scrollIntoView();             }         }           );         });     </script> </head>  <body class="tundra">     <div id="container" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design: 'headline', gutters: false">         <div id="map" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'center'"></div>         <div id="bottomPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'">             <div id="grid"></div>         </div>     </div> </body> </html> 
0 Kudos
TracySchloss
Honored Contributor
I don't know why, but this did not work for me in my initial grid creation.  I ended up with data that loaded into my grid that started with "C" and not "A".  But I took the lines of code and put them in my saveGridCSV function and they behaved just fine there. 

  function saveGridCSV(gridData){
    var fName;
     if (gridData) {
      var gridLength = gridData.store.data.length;
      dataArray.length = 0; 
      fieldNames.length = 0;
      var fieldValue = "";   
      var gridColumns = gridData.columns;
      var fieldHeaders = ["ID", "County", "Acres Treated", "Pct Area Treated", "Pct Change 2002-2007"];
      for (var col in gridColumns) {
       fieldNames.push(col);
      }
  var lastCol = fieldNames.length -1;
  var lastField = fieldNames[lastCol];
  dataArray.push(fieldHeaders.toString()+ " \n");
      var gridStore = gridData.store;
        var object = gridStore.query(function (item) {
          return item;
          }, { sort: [{ attribute: "NAME" }] });
var newStore = new Memory({ data: object });

    //steps through each record, pushes the values into an array that is formatted for CSV compatibility
        for (var i = 0; i < gridLength; i++) {
          var gridRow = newStore.data;
            arrayUtils.forEach(fieldNames, function(fieldName){
                fieldValue = gridRow[fieldName];
                var stringValue = String(fieldValue);
                if (stringValue.indexOf(",") > 0) { //removes any commas from data                    
                    stringValue = stringValue.replace(/,/g, " ");
                }
                if (stringValue.indexOf('\'') != -1 || stringValue.indexOf('\"') != -1) { //removes any slashes from data
                    //  console.log ("Data has a slash in it. Not sure of this section of the code!");
                    if (stringValue.indexOf('\"') != -1) {
                        stringValue = stringValue.replace("\"", "\"\"");
                    }
                    stringValue = "\"" + stringValue + "\"";
                }
                if (fieldName == lastField) {
                    dataArray.push(stringValue + " \n");//adds a new line when value is from the last field
                } else {
                    dataArray.push(stringValue);//otherwise just adds the value
                }
            });
        }//one row pushed to array     
        var data = dataArray.join();
        var inputData = data.replace(/\n,/g, "\n");//some clean up to get rid of the leading commas in the data
     
        submitCSVprint(gridData.id, inputData);
    } else {  //nothing to save
       alert ("Error saving data.");
    }
  }


The only thing left I want to do is drop off the OBJECTID out of the store in this function.  I need it for my initial grid because I have a click event using that ID.  I don't really want it in my CSV output.  Now that my data is sorted alphabetically by county, that OBJECTID looks even more out of place.
0 Kudos
TracySchloss
Honored Contributor
Never mind, I figured that out too.  When making my array of field names, I just needed to exclude OBJECTID with an if statement.
0 Kudos