0

I have the following problem, and am hoping someone here can enlighten me on a more suitable solution. Firstly I am trying to populate 12 form objects from the results of a CFC call in ajax. I am if/else over the returned set and populating each DOM object value by its description returned from the CFC, there must be a more simplistic way of doing this. Let me show you the support components and then the ajax call I think could be done better;

getValue() is used in jQueryUtils.js to call SessionMgr.cfc to get the session variable value;

function getValue(a) {
    var result = undefined;

        $.ajax({
                url: "cfc/SessionMgr.cfc",
                async: false,
                type: "get",
                dataType: "text",
                data: {
                    method: "getValue",
                    variablename: a
                },
              success: function(response) {
                  result = response;
                  //console.log('getValue: ', a , ' value: ' , response);
              },
              error: function(jqXHR, status, error) {
                  console.log('Error Occurred');
                  console.log(error);
              }
          });
    return result;
 }

that calls the SessionMgr.cfc;

<cffunction name="getValue" access="remote" returntype="string" returnformat="plain" output="yes" hint="I get the value of the given user-specific variable.">
    <cfargument name="variablename" type="string" required="yes">
    <cfreturn session[arguments.variableName] />
</cffunction>

then the following function call;

function getAllNodeValues() {

    var lID =        getValue('lID');
    var nID =        getValue('nID');
    var rLocation =  getValue('rLocation');
    var rMonth =     getValue('rMonth');
    var rYear =      getValue('rYear');
    var rStartDate = getValue('rStartDate');
    var rEndDate =   getValue('rEndDate');

        $.ajax({
            url: "cfc/Nodes.cfc",
            type: "get",
            async: false,
            dataType: "json",
            data: {
                Method: "GetAllNodeValues",
                LineID: lID,
                LineNodeID: nID,
                DCID: rLocation,
                Month: rMonth,
                Year: rYear,
                StartDate: rStartDate,
                EndDate: rEndDate
            },
          success: function(response) {
              $.each(response.DATA, function(i, row) {
                  // get value of first row as descriptions;
                  var val = row[0];
                  var descr = row[1];
                  // append new options
                  if(descr == 'IsActive') {
                      $('#cboNodeIsActive').val(val);
                  } else if(descr == 'OpCode') {
                      $('#cboNodeOpCode').val(val);
                  } else if(descr == 'IsUnits') {
                      $('#txtNodeIsUnits').val(val);
                  } else if(descr == 'Fractal') {
                      $('#cboNodeFractal').val(val);
                  } else if(descr == 'Ordinal') {
                      $('#txtNodeOrdinal').val(val);
                  } else if(descr == 'ParentID') {
                      $('#cboNodeParentID').val(val);
                  } else if(descr == 'Constant') {
                      $('#cboNodeConstant').val(val);
                  } else if(descr == 'ConstantValue') {
                      $('#txtNodeConstantValue').val(val);
                  } else if(descr == 'CurrentBalance') {
                      $('#txtNodeCurrentBalance').val(val);
                  } else if(descr == 'EndingBalance'){
                      $('#xtxNodeEndingBalance').val(val);
                  } else if(descr == 'CurrentUnits'){
                      $('#txtNodeCurrentUnits').val(val)
                  } else if(descr == 'EndingUnits'){
                      $('#txtNodeEndingUnits').val(val);
                  }
              });
          },
          error: function(msg) {
              console.log(msg);
          }
      });   
    }

returns this dataset; ReturnedDataset Because of the naming convention of my DOM objects, this seemed like the only way to set them was by if/else'ing over during the $.each() event. If someone has a better way of going directly to an array, or any improvement over the way it is being done here, would be appreciated.

so the JSON object returned has COLUMNS and DATA, how to I evaluate the COLUMNS in the if/else and then get the DATA value that corresponds to the array reference?

so, I added this to my success: callback;

 var i = 0;
              var col = [];
              var dat = [];
              col = response.COLUMNS;
              dat = response.DATA;
              console.log('col ', col);
              console.log('dat ',dat);

and this is the console results, consoleDump

what I dont understand is why is DATA nested a layer deeper than COLUMNS, and then how do I match-up the column name to the value in data into pairs that I can evaluate one and set my DOM object to the other?

BigBear
  • 59
  • 4
  • Aside from this issue, you need to remove `async: false` from the AJAX request. It's incredibly bad practice, the browser will be showing you a warning about it in the console, and it's not needed anyway. – Rory McCrossan Mar 19 '20 at 13:26
  • everyone of the answers to my questions here were very explicit on adding async: false, could you elaborate on why its bad practice? – BigBear Mar 19 '20 at 13:40
  • The primary reason is because it hangs the browser while the request is in progress. If your server is slow to respond this will appear to the user that the browser has crashed, and in some cases cause the OS to kill the browser process. In short, always use the async pattern when dealing with AJAX, whether that's by using callbacks or promises. More [here](https://stackoverflow.com/a/16569628/519413) – Rory McCrossan Mar 19 '20 at 13:43
  • IIRC `async : false` is deprecated with promises as of 1.8, but can still be used with callbacks. That said, you normally don't *want* to use synchronous calls because they'll block. – SOS Mar 20 '20 at 00:59

1 Answers1

2

what I dont understand is why is DATA nested a layer deeper than COLUMNS, and then how do I match-up the column name to the value in data into pairs that I can evaluate one and set my DOM object to the other?

The JSON serialization in ColdFusion is tied to the UI widgets that ship with it. Most devs have moved away from those UI tags, but the problem is then converting a query object to a more standard JSON format. I created a CFC to handle that.

serializeJSON( someQuery )

will return in this format:

{
  "COLUMNS":["BOOKID","TITLE","GENRE"],
  "DATA":[
    [8,"Apparition Man","Fiction"],
    [2,"Shopping Mart Mania","Non-fiction"]
  ]
}

This CFC will convert a query object to an array of arrays or an array of structs (JSON objects):

{
  "data":[
    {"bookid":8,"genre":"Fiction","title":"Apparition Man"},
    {"bookid":2,"genre":"Non-fiction","title":"Shopping Mart Mania"}
  ]
}

By default, the CFC lower cases all column names. You can adjust it to keep the column names in their current case if you like. You could then use jQuery to select all fields in a form by the form's ID and map the JSON keys to the field IDs. I'm sure there are other ways to accomplish that task without manually mapping the data to the fields one at a time.

Adrian J. Moreno
  • 14,350
  • 1
  • 37
  • 44
  • 1
    For CF11+ you can also use [application settings](https://cfdocs.org/application-cfc) to change the default for queries. [This link](https://stackoverflow.com/a/57878346/8895292) is for Lucee, but applies to CF as well. – SOS Mar 20 '20 at 01:02