difference between dojo.forEach vs. arrayUtil.forEach, do I need a deferred now?

5425
9
11-26-2013 05:05 AM
TracySchloss
Frequent Contributor
I started this as a reply to the thread about printing/saving a grid to CSV, but I'm not sure my problem is with that portion of my code.  I have several grids that I'd like to save as CSV.  In my non-AMD version, I had a dojo.forEach loop.  The data each grid is processed into a string, which is the input to the function that does the actual saving.

in pseudoCode
function exportGridCSV() {
//where qTaskNameList is an array of the names of all the grids I created
    dojo.forEach(qTaskNameList, function(gridName) {
var gridData = dijit.byId(gridName+"_grid");
...
code to that takes the data from the grid, creates output string called inputData; 
...
submitCSVPrint (gridName, inputData);
});
}

In this non-AMD version, the function loop processes each of my grids and I end up a dialog for "Save As" or "Open With" for each of the grids I processed in the dojo.forEach loop.

In the AMD version, I can put log entries and it seems to be looping through each grid, but I only ever get one "Save As" dialog. I think this is maybe because I'm now in asynchronous mode?
function exportGridCSV() {

    arrayUtil.forEach(qTaskNameList, function(gridName) {
var gridData = registry.byId(gridName+"_grid");
...
code to that takes the data from the grid, creates an output string called inputData; 
...
submitCSVPrint (gridName, inputData);
});
}


Do I need to set up some sort of deferred for this?  I didn't expect this behavior, I thought dojo.forEach and arrayUtil.forEach were more the same.
0 Kudos
9 Replies
JonathanUihlein
Esri Regular Contributor
Try something like:

function exportGridCSV() {
  qTaskNameList.forEach(function(gridName){
    var gridData = registry.byId(gridName+"_grid");
    //code to that takes the data from the grid, creates an output string called inputData; 
    submitCSVPrint (gridName, inputData);
  });
}


Another example, this is a loop I use that removes graphics from my graphicsLayer based on the type attribute
this.graphicsLayer.graphics.forEach(lang.hitch(this, function (g) {
    if (g.attributes) {
        if (g.attributes.type === i18n.customLabel) {
            this.graphicsLayer.remove(g);
        }
    }
}));
0 Kudos
TracySchloss
Frequent Contributor
That sounded promising, but it didn't help.  I can put a console.log right before I call the function to submit the print and see that I have 4 different inputData strings corresponding with my 4 grids.

Maybe my problem lies elsewhere.  I have a form that I'm using to manage the call to the script that does the actual saving.  I had to change it too to be in AMD format.  I'm not familiar with forms, so maybe the change here is the problem. 

non-AMD - HTML
<div>
<form data-dojo-type="dijit.form.Form" method="post" action="" style="height: 0px; width: 0px; display:none;" class="dlform" id="downloadForm" target="_blank">
<input type="hidden" name="report" class="ri" id="reportinput" value="" />
<input type="hidden" name="filename" class="fn" id="filename" value="" />

</form>
 <button id="btnExportGridCSVsubmit" dojotype="dijit.form.Button" onClick="exportGridCSV();"title="Save Search Results to CSV file">Save List</button>  
</div>

function that executes on the click
function submitCSVprint(gridName, inputData) {
//opens the data in a hidden form used for printing and allows the user to either open or save the file.
var url = "webservices/csv.ashx";
var f = dojo.byId("downloadForm");
f.action = url;
dojo.byId("reportinput").value = inputData;
var distType = dijit.byId("distTypeSelect").value;
var distNum = dojo.byId("txtDistNumber").value;
dojo.byId("filename").value = distType+"Dist_"+distNum+"_"+gridName;
f.submit();
}



One of the things I had to do when I switch to AMD was put the action of the form in it's construction, it didn't like having it added as the action within a function.  I was getting a 405 Server Error.
AMD version - HTML
<div>
<form id="downloadForm" data-dojo-type="dijit/form/Form" method="post" action="webservices/csv.ashx" class="dlform"  target="_blank">
<input type="hidden" name="report" class="ri" id="reportinput" value="" />
<input  type="hidden" name="filename" class="fn" id="filename" value="" />

</form>

</div>

and the function
function submitCSVprint(gridName, inputData) {    
    var f = registry.byId("downloadForm");
    dom.byId("reportinput").value = inputData;
    var outFileName = setOutName(gridName);
    dom.byId("filename").value = outFileName;
    f.submit();
}
function setOutName (gridName) {
    var distType = registry.byId("distTypeSelect").value;
    var distNum = registry.byId("txtDistNumber").value;
    var outFileName = distType+"Dist_"+distNum+"_"+gridName;
 //  console.log("outFileName is " + outFileName);
    return outFileName;
}


Maybe the submit to a AMD dijit/form/Form behaves differently than the non-AMD version?

I wish I had the hang of using gitHub, so I could post these there.  I have these on our test server, which you should be able to get to.  No guarantee that I haven't broken it worse before anyone gets a chance to look at it. 
non AMD version https://ogitest.oa.mo.gov/LEGIS/printExample/index.html

AMD version
https://ogitest.oa.mo.gov/LEGIS/LegislativeAnalysis/index.html

You'll need to turn on some layers first and then do a search on a district number.  The idea is to dynamically change what is queried and displayed.  That part of working, but there's no way I'm going to get away with leaving out a print or save function.
0 Kudos
JonathanUihlein
Esri Regular Contributor
Hey Tracy,

I can take a look at your application now.

While I do that, if you don't mind me asking, why didn't the forEach loop work?
What is qTaskNameList exactly as far as structure goes?
Does this not loop the same number of times as qTaskNameList.length?
0 Kudos
TracySchloss
Frequent Contributor
qTaskNameList is created when I execute the queryTasks, which is based on the current number of visible layers in the TOC.  It does seem to be looping the required number of times.  I can put break points or console.log entries throughout and see that I'm generating multiple data strings, each starting with the correct column headers followed by rows of data.  What I think should happen is that as soon as the string is formatted, it would be passed to the submitCSVprint function, where the data would be saved,  and then loop back to process the next grid. 

At first I thought the function subCSVprint was only running one time,  but I put some breakpoints into it as well and it is getting called multiple times.  It's more like the form.submit is only executing once.   That the act of the saving breaks out of the loop.

It's probably a curly brace in the wrong place or something equally as hard to spot.  Wouldn't that be nice?
0 Kudos
TracySchloss
Frequent Contributor
I don't find myself saying this very often, but it works fine in IE 8.  In Firefox, it looks to be saving the first grid's data.  In Chrome it looks to be the last grid's data.

In IE, the titlePane containing the save button is not a separate pane!  The button appears at the end of the previous titlePane.  There must be something in the definition of the form that IE really doesn't like.  BUT it works when I click it ....

It just gets stranger and stranger.
0 Kudos
MatthewLofgren
Occasional Contributor
Perhaps only one form submission is allowed? The page seems to do a refresh. Also, I don't think forEach guarantees order, which could be the browser discrepancy. I could be wrong.

Some alternatives:

Package all of the outputs together with one form submit and parse it on the .ashx page.

Make one or multiple ajax (post) calls to the .ashx page rather than using a form submit.
0 Kudos
TracySchloss
Frequent Contributor
I"m not sure if it's just one submission allowed or if the first submission is just preventing the rest from completing.  I'm thinking it's the behavior of the action of the form, because the script hasn't changed.  I agree with the order of the processing being inconsistent across the browsers, that's why I'm seeing the first set of data in Firefox, but the last when I try it in Chrome. 

Incidently, I didn't write the csv.ashx script I'm using, I got it from here http://gis.stackexchange.com/questions/67862/export-dojo-datagrid-results-to-csv-in-javascript-web-a...  I don't know the scripting language at all and I'm not going to be learning it just to get this to work.   All I know is it says c# in the header.  I followed the instructions from that thread and it had been working (in a non-AMD version).  Sometimes updating your code is a painful process...
0 Kudos
MatthewLofgren
Occasional Contributor
Could try something like this:

function submitCSVprint(gridName, inputData) {    
    //var f = registry.byId("downloadForm");
    //dom.byId("reportinput").value = inputData;
    var outFileName = setOutName(gridName);
    //dom.byId("filename").value = outFileName;
    //f.submit();
 
 require(["dojo/request"], function(request){
  request.post("webservices/csv.ashx", {
   data: {
    report: inputData,
    filename: outFileName
   }
  }).then(function(text){
   console.log("it worked");
  });
 }); 
}
0 Kudos
TracySchloss
Frequent Contributor
That didn't generate an error, but it didn't save anything either.  I just got multiple entries in the console.log of 'it worked' but it really didn't.
0 Kudos