Clip and ship by a queried layer extent and by user defined extent

688
7
04-02-2014 01:05 PM
AlexGole1
New Contributor II
I am trying add a functionality to the clip and ship script. I would also like the users to extract data by the extent of a queried feature layer. For instance, if County = "Alameda" then extract data that falls only within the Alameda county extent. Else, allow the users to hand draw an selection area. Here is my script but my testing conditions don't work correctly. My condition test as shown below does not work properly:

//variable that calls the textbox value
    var type = document.getElementById("textbox").value;
    
    //Set up the query per type
    var queryTask = new esri.tasks.QueryTask("http://sampleserver4.arcgisonline.com/ArcGIS/rest/services/HomelandSecurity/Incident_Data_Extraction/MapServer/2");  
    var query = new esri.tasks.Query();
    query.returnGeometry = true;
    
    //field to query
    query.outFields = ["ftype"]; 
    
    //execute query
    function executeQueryTask(type) {
    query.where = "ftype = " + type; 
    
    //If you want a result handler function, just replace that here
    queryTask.execute(query, function(featureSet){
        //This is designed to get the FIRST feature graphic as a JSON in the return because I am assuming you only have one county with that name
     var AOI = featureSet.features[0].geometry.toJSON(); 
    });
    }
    
    
    //First Area of interest selected by the client
    var Area = new FeatureSet();
    var features = [];
    features.push(map.graphics.graphics[0]);
    Area.features = features;

    if (executeQueryTask) {
     var params = {
     "Layers_to_Clip": clipLayers,
     "Area_of_Interest": AOI,
     "Feature_Format": registry.byId("formatBox").get("value")
    };
    }
    else {
     var params = {
     "Layers_to_Clip": clipLayers,
     "Area_of_Interest": Area,
     "Feature_Format": registry.byId("formatBox").get("value")
    };
    }
0 Kudos
7 Replies
TimCollyer
Occasional Contributor
I'm not familiar with the sample you referenced, but after a quick look at your code and I think there are few issues here...

1) You need to include the brackets to call a function. So where you have "if (executeQueryTask)", this should read "if (executeQueryTask())" if you want it to call your function. As it stands, it will always return true.

2) executeQueryTask() returns nothing, so if you do call it from your if statement, it will always return false.

3) queryTask.execute() is asynchronous, so if you do call executeQueryTask in your "if" statement, it will not wait queryTask.execute() to complete before returning.

4) You are declaring AOI within the scope of the callback function on queryTask.execute(). It will not be accessible in other areas of your code. You should declare this outside the callback function and then assign it within the callback function.

I think what you probably want to do is include all that code inside the call back function, so the callback function will look something like this

queryTask.execute(query, function(featureSet){
    
    var Area = new FeatureSet();
    var features = [];
    features.push(map.graphics.graphics[0]);
    Area.features = features;                        
    
    var params = {
        "Layers_to_Clip": clipLayers,
        "Feature_Format": registry.byId("formatBox").get("value")
    };                        
    
    if (featureSet.features.length > 0) {
        var AOI = featureSet.features[0].geometry.toJSON(); 
        params.Area_of_Interest = AOI;
    } else {
        params.Area_of_Interest = Area;
    }
    
    // now do something with "params" here
    
});


edit: Actually, there is still a question of what you want params.Area_of_Interest to actually be? In one case you are setting it to be a geometry string with: featureSet.features[0].geometry.toJson()... in the other case you are setting it to be a FeatureSet.
0 Kudos
AlexGole1
New Contributor II
I'm not familiar with the sample you referenced, but after a quick look at your code and I think there are few issues here...

1) You need to include the brackets to call a function. So where you have "if (executeQueryTask)", this should read "if (executeQueryTask())" if you want it to call your function. As it stands, it will always return true.

2) executeQueryTask() returns nothing, so if you do call it from your if statement, it will always return false.

3) queryTask.execute() is asynchronous, so if you do call executeQueryTask in your "if" statement, it will not wait queryTask.execute() to complete before returning.

4) You are declaring AOI within the scope of the callback function on queryTask.execute(). It will not be accessible in other areas of your code. You should declare this outside the callback function and then assign it within the callback function.

I think what you probably want to do is include all that code inside the call back function, so the callback function will look something like this

queryTask.execute(query, function(featureSet){
    
    var Area = new FeatureSet();
    var features = [];
    features.push(map.graphics.graphics[0]);
    Area.features = features;                        
    
    var params = {
        "Layers_to_Clip": clipLayers,
        "Feature_Format": registry.byId("formatBox").get("value")
    };                        
    
    if (featureSet.features.length > 0) {
        var AOI = featureSet.features[0].geometry.toJSON(); 
        params.Area_of_Interest = AOI;
    } else {
        params.Area_of_Interest = Area;
    }
    
    // now do something with "params" here
    
});


edit: Actually, there is still a question of what you want params.Area_of_Interest to actually be? In one case you are setting it to be a geometry string with: featureSet.features[0].geometry.toJson()... in the other case you are setting it to be a FeatureSet.


Thanks a lot for this detailed explanation! That very helpful! To your question "what you want params.Area_of_Interest to actually be?" I would like the user to be able to choose between 2 AOI. If the user click on the free-hand polygon then the user will draw the extent else the user will have to query a layer to define the extent (for example: if county="Alameda" then the extent will be the Alameda county polygon). I would like the users to have these two extent choices.
I am going to correct the errors you have noticed in my code.
Thank you for your help.
Alex
0 Kudos
TimCollyer
Occasional Contributor
You just need to be careful because you define "Area" as a FeatureSet and assign that to params.Area_of_Interest, but you also assign featureSet.features[0].geometry.toJson() to params.Area_of_Interest and this is a geometry.

You should decide which type you want to assign, a FeatureSet or a geometry.

Probably what you want is just something like this


queryTask.execute(query, function(featureSet){
    
    var Area = new FeatureSet();
    var features = [];
    features.push(map.graphics.graphics[0]);
    Area.features = features;                        
    
    var params = {
        "Layers_to_Clip": clipLayers,
        "Feature_Format": registry.byId("formatBox").get("value")
    };                        
    
    if (featureSet.features.length > 0) {
        var AOI = featureSet.features[0].geometry; 
        params.Area_of_Interest = AOI;
    } else {
        params.Area_of_Interest = map.graphics.graphics[0].geometry;
    }
    
    // now do something with "params" here
    
});
0 Kudos
AlexGole1
New Contributor II
You just need to be careful because you define "Area" as a FeatureSet and assign that to params.Area_of_Interest, but you also assign featureSet.features[0].geometry.toJson() to params.Area_of_Interest and this is a geometry.

You should decide which type you want to assign, a FeatureSet or a geometry.

Probably what you want is just something like this


queryTask.execute(query, function(featureSet){
    
    var Area = new FeatureSet();
    var features = [];
    features.push(map.graphics.graphics[0]);
    Area.features = features;                        
    
    var params = {
        "Layers_to_Clip": clipLayers,
        "Feature_Format": registry.byId("formatBox").get("value")
    };                        
    
    if (featureSet.features.length > 0) {
        var AOI = featureSet.features[0].geometry; 
        params.Area_of_Interest = AOI;
    } else {
        params.Area_of_Interest = map.graphics.graphics[0].geometry;
    }
    
    // now do something with "params" here
    
});


Good point, I think featureset is the one.
That is what the GP tool is looking for :

Parameter: Area_of_Interest
Data Type: GPFeatureRecordSetLayer
Display Name Area of Interest
Description: One or more polygons by which the layers will be clipped.
Direction: esriGPParameterDirectionInput
Default Value:
Geometry Type: esriGeometryPolygon
HasZ: false
HasM: false
Spatial Reference: null

I am experiencing issues implementing your code for some reasons (maybe I am too new to JS). here is my code to which i added your script here. The layout is completely messed up. Thanks
0 Kudos
TimCollyer
Occasional Contributor
It looks like there are quite a few issues with your code.

Some that jump out...

- It doesn't look like your main BorderContainer has a closing tag.
- Your javascript is all messed up. You are missing closing parenthesis and braces.
- It doesn't look like you've defined the function "executeQueryTask" which you set as the callback on the click of your Query button

Go through your javascript carefully and make sure that all your braces and parenthesis are opening and closing where they should be.

When you load your page, you can open the developer tools of whatever browser you are using and it will report a lot of these errors.
0 Kudos
TimCollyer
Occasional Contributor
Also, it doesn't look like you're waiting for your DOM and all of your widgets/components to finish loading before you start trying to access them.

I usually just use data-dojo-config="praseOnLoad: true" to do this to make sure the document gets parsed when the page loads and then wrap my loading function inside a dojo/ready which makes sure that all the required widgets have laoded. See here and here for more info on this.

It would look something like this (I took out your TOC, but you should be able to add it back in when you run it in your environment).

http://jsbin.com/ficetiwo/1/edit
0 Kudos
AlexGole1
New Contributor II
Also, it doesn't look like you're waiting for your DOM and all of your widgets/components to finish loading before you start trying to access them.

I usually just use data-dojo-config="praseOnLoad: true" to do this to make sure the document gets parsed when the page loads and then wrap my loading function inside a dojo/ready which makes sure that all the required widgets have laoded. See here and here for more info on this.

It would look something like this (I took out your TOC, but you should be able to add it back in when you run it in your environment).

http://jsbin.com/ficetiwo/1/edit


I am new to JS and JS debuggers. I use firebug but i did not notice the missing braces  and parenthesis. It seems like you greatly improved my script. I thought that 
 parser.parse();
was parsing on load. Also I was unaware of the module
"dojo/ready"
. So thank you!

Now the script seems to run fine to the exception of the extract data function.

It seems like I need a new test (if...else) somewhere. When I submit a querytask to execute then it always returns this message " Select layers to extract and draw an area of interest."
if ( clipLayers.length === 0 || map.graphics.graphics.length === 0 ) {
                   alert("Select layers to extract and draw an area of interest.");
                return;


but never runs the query. Also when I draw a graphic with the hand drawn polygon (extent) tool, then it  does not seem to push the ClipLayers to be extracted to the GP tool anymore. I am unsure why.

Thank you for all your precious help.
Alex
0 Kudos