3

I have a query (see this jsbin example) to find the percentile rank of a fields value. So it finds all records (N) and then how many records are less than itself (k). Percentile = k/N as a rounded percent.

The math is working correctly, but I would like to use the whole thing a function to which I could pass arguments for field name and field value when you click on features.

My problem is this: I have the listeners for selecting features outside of the AMD module where I have the query. So if the listeners call this percentile function, it is undefined. However, if I move this function outside the AMD module, then query and QueryTask are undefined, because I set those up in the module.

I'm new to Javascript modules, so I'm hoping to find out if there is a simple way I could avoid this problem. I've tried moving the listeners inside the AMD module, but that makes other functions undefined.

I may not be using the word module correctly here. I think what I'm experiencing is a scope problem. I have declared this function in one scope and I'm trying to access it in another. Is that the right way to think about it?

Here is the complete code:

function pctile(pctileField,pctileValue) {

    queryTaskN = new QueryTask("http://gis.datadrivendetroit.org/arcgis/rest/services/DetroitNeighborhoodMetrics/FeatureServer/0");
    queryN = new Query();
    queryN.where = '1=1';
    queryTaskN.executeForCount(queryN, storeResultsN);

    function storeResultsN(results) {
        N = results;
        console.log("N:",N);
    };

    queryTaskN.on("execute-for-count-complete", function() {
        queryTaskK = new QueryTask("http://gis.datadrivendetroit.org/arcgis/rest/services/DetroitNeighborhoodMetrics/FeatureServer/0");
        queryK = new Query();
        queryK.where = '"'+pctileField+'" > ' + pctileValue;
        queryTaskK.executeForCount(queryK, storeResultsK);

        function storeResultsK(results) {
            k = results;
            console.log("k:",k);
            p = k / N;
            console.log(p);
            P = p*100;
        };
    });
};
1

The two passed parameters are not recognized in the scope of the listeners.

You've mentioned that you declared a function inside the same AMD, so you have just to create globale variables and use them inside callback functions.

try this code: (results shown in console)

require([
  "dojo/parser","esri/tasks/QueryTask","esri/tasks/query",

], function(
  parser,QueryTask,Query
) {
  parser.parse();
  //declaring globale varibales N ,pctileField and pctileValue 
  this.N = 0;
  this.pctileField = "";
  this.pctileValue = "";

  queryTaskN = new QueryTask("http://gis.datadrivendetroit.org/arcgis/rest/services/DetroitNeighborhoodMetrics/FeatureServer/0");
  function pctile(pctileField,pctileValue) {
    // assigning passed arg values to the globale variable
    this.pctileField = pctileField;
    this.pctileValue = pctileValue;

    queryN = new Query();
    queryN.where = '1=1';
    queryTaskN.executeForCount(queryN, storeResultsN);
  }

  function storeResultsN(result){
    this.N = result;
    queryTaskK = new QueryTask("http://gis.datadrivendetroit.org/arcgis/rest/services/DetroitNeighborhoodMetrics/FeatureServer/0");
    queryK = new Query();
    queryK.where = '"'+this.pctileField+'" > ' + this.pctileValue;
    queryTaskN.executeForCount(queryK, storeResultsK);

  }

  function storeResultsK(results) {
        k = results;
        console.log("k:",k , "n :", this.N);
        p = k / this.N;
        console.log(p);
        P = p*100;
        console.log(P.toFixed(2)+"%");
  };

  // call attribute exemple !
  pctile("median_amount",60);

});
  • This seems helpful, but I'm actually trying to call the function pctile from outside the AMD. Like in this jsbin. Is that possible? – matthewiannowlin Feb 23 '16 at 11:34
  • Can you explain please , why you have to call that function outside the AMD module ! – Springer F Feb 23 '16 at 20:33
  • You know what, I can't replicate the problem I was having earlier this morning with your solution. It looks like what you suggested is correct. – matthewiannowlin Feb 23 '16 at 21:47
  • Here is why I wanted pctile() outside of the AMD. I'm using the results of pctile() in a function called changePopup, which replaces the HTML of my popup DIV. I declared changePopup globally, because I need to call it from my HTML file when the user makes a selection in a drop down menu. So: is there a way I can put pctile() and changePopup() inside the AMD, but still call changePopup() from the HTML? Can I do something like <select onchange="whateverTheAMDisCalled.changePopup()">? – matthewiannowlin Feb 24 '16 at 17:18
  • I've solved the above problem by declaring changePopup() as a global variable and the defining it as a function within the scope of the AMD. Then I can call it directly from the HTML. So my issues were mostly solved by having a better understanding of scope. – matthewiannowlin Feb 24 '16 at 19:03
1

My problem here was that I was trying to call the function pctile which was not in the scope in which I was calling it.

I think this pseudo code should explain it:

//set up AMD
require([some dependencies, including query and all other ESRI stuff I need...],
function(some functions, including query and all other ESRI stuff I need...) {
    function pctile(arguments) {a function using query...};
});
//end AMD
pctile(passing arguments);

This didn't work because percentile wasn't declared in the right scope. But if I moved pctile to the scope in which I called it, I could not use query and QueryTask, because they were set up in the AMD. However, because of some other issues, I couldn't move my other code into the AMD, either.

So, the solution was to set up nested AMDs. That way my pctile function could access query and QueryTask, and it was in the right scope when I needed to call it. Like so:

//set up AMD
require([some dependencies, including query...],
function(some functions, including query...) {
    function pctile(arguments) {a function using query...};
pctile(passing arguments);
    //set up nested AMD
    require([some dependencies, including all other ESRI stuff I need...],
    function(some functions, including all other ESRI stuff I need...) {
        do something...
    });
    //end nested AMD
pctile(passing arguments);
});
//end AMD

I don't know if this is ideal, but it gets the job done.

  • Great , if you are making packaged project (not only a single page ) so I think the best way to prevent this is to create your own Dojo Class than configure package referencing this last and use it directly by instantiate the class , and call all it's method – Springer F Feb 24 '16 at 11:15
  • Here is some resources : configuring packages and create classes – Springer F Feb 24 '16 at 11:17
  • Thanks. What's really stumping me now is when I try to use this percentile code to 1) calculate the percentile of a feature I've clicked on and then 2) use that percentile to generate some HTML for a popup, I can't seem to get it to work. I've posted that issue as a separate question. – matthewiannowlin Feb 24 '16 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.