1

I didn't write but rather I'm reviewing the following Lightning JS function:

InitializeComponent : function (component) {

        var recId = component.get("v.recordId");

        var action = component.get("c.Init");
        action.setParams({ "recordId" : recId });
        action.setCallback(this, function(response) {
            var resp = response.getReturnValue();
            if (component.isValid()) {

                if ($A.util.isEmpty(resp.RowData)) {
                    this.setErrorState(component, "No row data was returned for the Time Report");
                    return;
                }

                // move the root level node for the treeGrid
                resp.RowData[0]["_children"] = resp.RowData[0]["us_children"];
                delete resp.RowData[0]["us_children"];  

                // grab the root children and update the _children attribute for treeGrid requirements
                for (let x of resp.RowData[0]["_children"]) {
                    x["_children"] = x["us_children"];
                    delete x["us_children"];
                }
                component.set("v.initResponse",resp);
                this.HideSpinner(component);                
            }
        },"SUCCESS");

        action.setCallback(this, function(response) {
            this.setErrorState(component, response.getError()[0].message);
        },"ERROR");

        $A.enqueueAction(action);   

    }

It populates a lightning:treeGrid component.

I'm confused about what's happening in this part:

// move the root level node for the treeGrid
resp.RowData[0]["_children"] = resp.RowData[0]["us_children"];
delete resp.RowData[0]["us_children"];  

// grab the root children and update the _children attribute for treeGrid requirements
for (let x of resp.RowData[0]["_children"]) {
    x["_children"] = x["us_children"];
    delete x["us_children"];
}

again, resp = response.getReturnValue(). Drilling down into the value returned from the server as far as possible, resp.RowData[0] looks like this when debugging the server side action:

RowData:[BillableHours=37.50, 
         Name=Total, 
         NonBillableHours=0.5, 
         RowId=TOTALS, 
         TotalHours=null, 
         us_children=(RowData:[BillableHours=3.25, 
                               Name=John Doe, 
                               NonBillableHours=0, 
                               RowId=John Doe, 
                               TotalHours=null, 
                               us_children=(RowData:[BillableHours=3.25, 
                                                     Name=Project Management, 
                                                     NonBillableHours=0, 
                                                     RowId=John DoeProject Management, 
                                                     TotalHours=null, 
                                                     us_children=()])], 
                        RowData:[BillableHours=33.25, 
                                 Name=John Doe2, 
                                 NonBillableHours=0, 
                                 RowId=John Doe2, 
                                 TotalHours=null, 
                                 us_children=(RowData:[BillableHours=32.75, 
                                                       Name=Consulting Services, 
                                                       NonBillableHours=0, 
                                                       RowId=John Doe2Consulting Services, 
                                                       TotalHours=null, 
                                                       us_children=()], 
                                              RowData:[BillableHours=0.5, 
                                                       Name=Project Management, 
                                                       NonBillableHours=0, 
                                                       RowId=John Doe2Project Management, 
                                                       TotalHours=null, 
                                                       us_children=()])], 
                        RowData:[BillableHours=1.0, 
                                 Name=John Doe3, 
                                 NonBillableHours=0.5, 
                                 RowId=John Doe3, 
                                 TotalHours=null, 
                                 us_children=(RowData:[BillableHours=1.0, 
                                                       Name=Consulting Services, 
                                                       NonBillableHours=0, 
                                                       RowId=John Doe3Consulting Services, 
                                                       TotalHours=null, 
                                                       us_children=()], 
                                              RowData:[BillableHours=0, 
                                                       Name=Project Management, 
                                                       NonBillableHours=0.5, 
                                                       RowId=John Doe3Project Management, 
                                                       TotalHours=null, 
                                                       us_children=()])])]

Debugging the client side, resp.RowData[0]["_children"] starts out undefined and resp.RowData[0]["us_children"] is:

enter image description here

So:

Does resp.RowData[0]["_children"] = resp.RowData[0]["us_children"]; actually, on the spot, create a "_children" item at the 0 index and simultaneously sets it equal to resp.RowData[0]["us_children"]?

At any rate, what's going on in the loop?

And don't resp.RowData[0]["_children"] and resp.RowData[0]["us_children"] imply named indices - "_children" and "us_children" respectively? If so, I thought they weren't allowed in JS?

2

This inefficient code is working around an Apex limitation that variable names may not start with an underscore ("_"), yet lightning:treeGrid requires _children in order to show the child elements. Their solution was to have a variable named us_children, that they then recursively strip off the us in front and delete the original keys. In JavaScript, practically anything can be a key, so long as it is contained in an Object, usually denoted as {}. This is contrast to an Array, usually denoted as [], which is meant to hold only numeric indexes, as you'd expect.

This code expects the data to be no more than 2 layers deep; anything more than that won't properly translated, and will not appear as increasing grid levels. In addition, it also automatically assumes one top-level element in the list. While this is all fine, it's incredibly fragile and certainly not as clean as it could be. With a simple recursive function, this could all be fixed up easily:

resp.RowData.forEach(function recurse(item) {
    if(item.us_children) {
        item.us_children.forEach(recurse);
        item._children = item.us_children;
        delete item.us_children;
    }
});

While this is about the same lines of code, it (hopefully) makes it clear that we're recursively moving us_children to _children.

2

Here's my take.

For your question:

Does resp.RowData[0]["_children"] = resp.RowData[0]["us_children"]; actually, on the spot, create a "_children" item at the 0 index and simultaneously sets it equal to resp.RowData[0]["us_children"]?

Yes. In lightning:treeGrid, if you want to display nested components those are in your response data, you will need to use the _children keyword. It's not an index but a key at a particular index, that's used by the platform to traverse through the nested contents.

Here's what is says in the documentation:

Nested items must be defined using the _children key.


And don't resp.RowData[0]["_children"] and resp.RowData[0]["us_children"] imply named indices - "_children" and "us_children" respectively? If so, I thought they weren't allowed in JS?

I am not completely aware of JS named indices, but in this case, it does not seem to be an index but the key defined with the name _children at the element at that particular index.


At any rate, what's going on in the loop?

As far as I can understand, within the loop, its just traversing through all the nested children at 0-th index, and then updating the node with the contents from us_children and deleting the us_children node details, so that all nested child elements are traversed by the component just by using _children keyword.

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.