Popup content w/ Relationship Query

1041
18
Jump to solution
02-26-2019 11:20 AM
MollyFoley
Regular Contributor

I'm going to ask a pretty much straight JS question because stackexchange can't wrap their minds around the fact that there are javascript platforms that they've never seen before (arcigs javascript api basically).... so, sorry this is going to be a bit out of place but hopefully someone here will understand what I'm saying better.

I am trying to populate a InfoTemplate object with content using related table records of a polygon layer. I run the relationship query sucessfully, and then I need to loop through the records and put them in an HTML table format so I can display it in the popup. The problem I'm having is that I'm not sure how to write the code so the asynchronous relationship query finishes before the popup content gets rendered. The anonymous callback function won't finish before the return statement is hit in the function, thus my popup renders the table headers but nothing else. I'm sure I could just shift around the code using a feature layer on click event and do it that way, but I feel that I'm so close to having it done this way that maybe there's a simpler fix.

I've fiddled around with JS Promises and moving the anonymous callback function to it's own named function, but just can't seem to figure out how to make those work together.

//Call the function that will format the popup content
mgmtTractPopupBox.setContent(mgmtPopupContent);

function mgmtPopupContent(feature) {
    //set up the query properties
    //....
    //Create table header that will go inside popup
    var content = '<table id="mgmtPopupTable1"><tr><th>Veg Mgmt Practice</th><th>Herbicide</th><th>Month</th><th>Year</th>\
            <th>Implemented By</th><th>Funded By</th><th>Farm Bill Code</th></tr>';
    //Run the query - asynchronous process
    queryableMgmtTractFL.queryRelatedFeatures(relatedQuery, function (relatedRecords) {
        var fset = relatedRecords[OID].features;
        fset.forEach(function (feature) {
            var vegPractice = vegPName(feature.attributes.VegMgmtPractice);
            var herbicide = herbName(feature.attributes.Herbicide);
            var monthTreated = monthName(feature.attributes.MonthTreated);
            var yearTreated = feature.attributes.YearTreated;
            var impBy = impName(feature.attributes.ImplementedBy);
            var fundBy = fundName(feature.attributes.FundedBy);
            var fbc = feature.attributes.FarmBillCode;
            if (fundBy == "CRP" || fundBy == "CRP - CREP") {
                fbc = crpName(fbc);
            }
            else if (fundBy == "EQIP" || fundBy == "EQIP - RCPP") {
                fbc = eqipName(fbc);
            }
            else {
                fbc = "Not applicable";
            }
            row = '<tr><td>' + vegPractice + '</td><td>' + herbicide + '</td><td>' + monthTreated + '</td><td>' + yearTreated +
                '</td><td>' + impBy + '</td><td>' + fundBy + '</td><td>' + fbc + '</td></tr>';
            content = content + row;
        });
        content = content + '</table>';
    });
    return content; //Returns table header with none of the derived rows 
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
1 Solution

Accepted Solutions
MollyFoley
Regular Contributor

Figured it out... dumb SQL mistake, using the javascript operator of "or" instead of the SQL operator of "or" in my definition expression. Final code that's FINALLY working. With the records that come out of the initial query task (on hbMgmtTableFL), I should be able to set the popup with those values for each polygon that is visible on the map. I'll have to format the popup on click of a feature with another ".queryRelatedFeatures(...)" call.

//After adding the layers to the map get the initial definition expression of the tract feature layer
map.on("layers-add-result", function () {
    getDefinitionExpression();
});

function getDefinitionExpression() {
    var recordIDs = new Query();
    recordIDs.where = "1=1";
    hbMgmtTableFL.queryIds(query, function (OIDs) {
        //Create relationship query
        var relatedRecordsQuery = new RelationshipQuery();
        relatedRecordsQuery.objectIds = OIDs;
        relatedRecordsQuery.outFields = ["MgmtTractID"];
        relatedRecordsQuery.relationshipId = 0;
        hbMgmtTableFL.queryRelatedFeatures(relatedRecordsQuery, function (fset) {
            //Get all MgmtTractIDs for the current year
            var MgmtTractIDsArr = [];
            for (i = 0; i < OIDs.length; i++) {
                var OID = OIDs[i];
                var feature = fset[OID].features;
                var mgmtTractId = feature[0].attributes.MgmtTractID;
                if (!(MgmtTractIDsArr.includes(mgmtTractId))) {
                    MgmtTractIDsArr.push(mgmtTractId);
                };
            }
            //Create the definition expression
            var whereClause;
            for (i = 0; i < MgmtTractIDsArr.length; i++) {
                if (i == 0) {
                    whereClause = "MgmtTractID = '" + MgmtTractIDsArr[i] + "'";
                }
                else {
                    whereClause = whereClause + " OR MgmtTractID = '" + MgmtTractIDsArr[i] + "'";
                }
            }
            //Set the polygon feature layer's definition expression based on the GUIDs
            hbMgmtTractFL.setDefinitionExpression(whereClause);
            hbMgmtTractFL.refresh();
        });
    });
};‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

View solution in original post

0 Kudos
18 Replies
RobertScheitlin__GISP
MVP Esteemed Contributor

Molly,

  Instead of have line 34 do the return have line 32 do the return.

0 Kudos
MollyFoley
Regular Contributor

If I move the return to line 34 (I think you misspoke in what lines you specified?), nothing gets printed to the popup. That return statement is inside the anonymous callback function and the return to get anything to show up in the popup is inside the mgmtPopupContent function.

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Molly,

  Yep line numbers are skewed when viewing in just the inbox.

Here is what I am suggesting:

function mgmtPopupContent(feature) {
    //set up the query properties
    //....
    //Create table header that will go inside popup
    var content = '<table id="mgmtPopupTable1"><tr><th>Veg Mgmt Practice</th><th>Herbicide</th><th>Month</th><th>Year</th>\
            <th>Implemented By</th><th>Funded By</th><th>Farm Bill Code</th></tr>';
    //Run the query - asynchronous process
    queryableMgmtTractFL.queryRelatedFeatures(relatedQuery, function (relatedRecords) {
        var fset = relatedRecords[OID].features;
        fset.forEach(function (feature) {
            var vegPractice = vegPName(feature.attributes.VegMgmtPractice);
            var herbicide = herbName(feature.attributes.Herbicide);
            var monthTreated = monthName(feature.attributes.MonthTreated);
            var yearTreated = feature.attributes.YearTreated;
            var impBy = impName(feature.attributes.ImplementedBy);
            var fundBy = fundName(feature.attributes.FundedBy);
            var fbc = feature.attributes.FarmBillCode;
            if (fundBy == "CRP" || fundBy == "CRP - CREP") {
                fbc = crpName(fbc);
            }
            else if (fundBy == "EQIP" || fundBy == "EQIP - RCPP") {
                fbc = eqipName(fbc);
            }
            else {
                fbc = "Not applicable";
            }
            row = '<tr><td>' + vegPractice + '</td><td>' + herbicide + '</td><td>' + monthTreated + '</td><td>' + yearTreated +
                '</td><td>' + impBy + '</td><td>' + fundBy + '</td><td>' + fbc + '</td></tr>';
            content = content + row;
        });
        content = content + '</table>';
        //You to not return anything untill the async process is done.
        return content;
    });
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
MollyFoley
Regular Contributor

Yes, I tried that but it doesn't do anything. It returns nothing to the popup window, not even the table headers because you're returning inside the callback function (function(relatedRecords){...}, not the mgmtPopupContent function. I need to return something from the mgmtPopupContent function since that is what the .setcontent() for the InfoTemplate object is set to:

mgmtTractPopupBox.setContent(mgmtPopupContent);‍‍

If you were to do two returns, one inside the anonymous callback function and then one inside the mgmtPopupContent function, it will just return the table headers before anonymous callback function is done.

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

OK. I will see if I can whip together a sample that works for this.

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Molly,

  The setContent method of a popup does not support a Deferred so it will not wait for something to finish running. So you have to program accordingly. do you show the popup based on a mouse click event?

Where are you calling 

mgmtTractPopupBox.setContent(mgmtPopupContent);

from?

0 Kudos
MollyFoley
Regular Contributor

Well that would make sense on why I am struggling so much  

I do show the popup based on a mouse click on the feature. I just have the content formatted at the start of the script and then assign that mgmtTractPopupBox variable to the infotemplate property of a feature layer I define later.

//Format the popup content for the habitat management tract feature layer
var mgmtTractPopupBox = new InfoTemplate();
mgmtTractPopupBox.setTitle("${HabitatManagement.DBO.MgmtTracts.StateID} Habitat Management Tract");
mgmtTractPopupBox.setContent(mgmtPopupContent);

//Add the habitat management tract feature layer with the join. This one is used to display on the map.
var hbMgmtTractFL = new FeatureLayer("https://xxx/rest/services/HabitatMonitoring/HabitatData/MapServer/dynamicLayer", {
    refreshInterval: 10,
    visible: false,
    source: lyrDataSource,
    outFields: ["*"],
    infoTemplate: mgmtTractPopupBox
});‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Possibly important to note, I define the popup on a dynamic layer but when I'm running the related features query, I query the same layer only it's a feature layer instead of a dynamic layer (the regular feature layer is also defined, called queryableMgmtTractFL as seen in my original post.

0 Kudos
RobertScheitlin__GISP
MVP Esteemed Contributor

Molly,

  So instead of assigning the infoTemplate ahead of time for the whole FeatureLayer add a on click event for the hbMgmtTractFL and do your relationship query first and then open the maps infowindow manually using the results of the relate query.

0 Kudos
MollyFoley
Regular Contributor

Wouldn't I just run into the same problem though? With a click event, you're still going to have to get the OID, set up the relationship query properties, do the relationship query and generate the popup content and somehow return that popup content to a variable, then define the InfoTemplate with the content set to that variable. That doesn't solve the problem of having nested functions and not being able to return things from the query to the parent function.

Anyway, after attempting this it keeps telling me my feature layer is undefined when trying to do this, it breaks my map too:

hbMgmtTractFL.on("click", function (feature) {
    for (var attrb in feature.attributes) {
        if (attrb == "HabitatManagement.DBO.MgmtTracts.OBJECTID") {
            var OID = feature.attributes[attrb];
        }
    }
    var relatedQuery = new RelationshipQuery();
    relatedQuery.outFields = ["*"];
    relatedQuery.relationshipId = 0;
    relatedQuery.objectIds = [OID];
    //Get data year that the map view is set to and set the definition expression on the table
    viewYear = dom.byId("data-year").value;
    relatedQuery.definitionExpression = "YearTreated = " + viewYear;
    //Run the query and format popup content
    var content = queryableMgmtTractFL.queryRelatedFeatures(relatedQuery, function (relatedRecords) {
        var fset = relatedRecords[OID].features;
        fset.forEach(function (feature) {
            var vegPractice = vegPName(feature.attributes.VegMgmtPractice);
            var herbicide = herbName(feature.attributes.Herbicide);
            var monthTreated = monthName(feature.attributes.MonthTreated);
            var yearTreated = feature.attributes.YearTreated;
            var impBy = impName(feature.attributes.ImplementedBy);
            var fundBy = fundName(feature.attributes.FundedBy);
            var fbc = feature.attributes.FarmBillCode;
            if (fundBy == "CRP" || fundBy == "CRP - CREP") {
                fbc = crpName(fbc);
            }
            else if (fundBy == "EQIP" || fundBy == "EQIP - RCPP") {
                fbc = eqipName(fbc);
            }
            else {
                fbc = "Not applicable";
            }
            row = '<tr><td>' + vegPractice + '</td><td>' + herbicide + '</td><td>' + monthTreated + '</td><td>' + yearTreated +
                '</td><td>' + impBy + '</td><td>' + fundBy + '</td><td>' + fbc + '</td></tr>';
            content = content + row;
        });
        content = content + '</table>';
        console.log(content);
        return content;
    });
    console.log(content);
    return content;
});
0 Kudos