2

I am trying to create a simple, reusable component that allows me to list related records in an easy to read way. I want to be able to use this component a few times on a single record, and I would like it to be able to be used for different target objects.

My basic thought is to pull the current record, define target parameters, do a server query, and then return the results through aura:iteration. I need to be able to create the server side controller in such a way that it can query for any object and return them the same way.

I have the code built, but right now I am getting a really generic Uncaught Error in $A.getCallback() [result is not defined] message. I've been googling what that could mean in my case and it seems to always be a typo or inconsistent variable names. If that is my problem, I am unable to find the issue.

I do wonder if the problem is the way I return the information from the server. Could the problem be the wrapper class being put into a list? That doesn't seem right....

Also, somewhat related. As you can tell from the name of the component, I had planned on iterating over lightning:tile because I thought that would look nice. But I can't seem to find an example of how that would be accomplished. Does anyone have any examples of iterating over lightning:tile?

Here is the code I have:


relRecordTiles.cmp

<aura:component controller="relRecordTilesController" access="global">
<!--<aura:attribute name="resultItems" type="Object" access="public"
                description="This attribute can be used by parent component to read selected records"/>   -->

<aura:attribute name="currentID" type="String" access="public" 
                description="ID of current record (which is the parent of the return values)"/>
<aura:attribute name="objectName" type="String" access="public" 
                description="Name of Object to be searched"/>
<aura:attribute name="lookupField" type="String" access="public" 
                description="Name of field that connects the child object to the parent (current record)"/>    

<aura:attribute name="field1" type="String" access="public" 
                description="API Name of the first field, to be used to show text"/>
<aura:attribute name="field1Label" type="String" access="public" 
                description="Label for the value returned"/>
<aura:attribute name="field2" type="String" access="public" 
                description="API Name of the second field, to be used to show text"/>
<aura:attribute name="field2Label" type="String" access="public" 
                description="Label for the value returned"/>
<aura:attribute name="field3" type="String" access="public" 
                description="API Name of the third field, to be used to show text"/>
<aura:attribute name="field3Label" type="String" access="public" 
                description="Label for the value returned"/>

<aura:attribute Name="serverResult" type="list" /> 

<aura:handler name="init" value="{!this}" action="{!c.doInit}" />    

<br/>
relRecordTiles should go here:
<div class="salesforce slds">
    <ul class="slds-has-dividers--around-space">
        <aura:iteration items="{!v.serverResult}" var="item">
            <li class="slds-item">
                <div class="slds-tile slds-tile--board">
                    <h3 class="slds-truncate"><a href="{! '# ' + objectName + '/' + item.Id}"> {!objectName}: {!item.Name}</a>  </h3>
                    <div class="slds-tile__detail slds-text-body--small">
                        <aura:if isTrue="{!not(empty(v.field1))}">
                            <p>{!field1Label}: {!item.field1}</p> <br/>
                        </aura:if>
                        <aura:if isTrue="{!not(empty(v.field2))}">
                            <p>{!field2Label}: {!item.field2}</p> <br/>
                        </aura:if>
                        <aura:if isTrue="{!not(empty(v.field3))}">
                            <p>{!field3Label}: {!item.field3}</p> <br/>
                        </aura:if>
                    </div>
                </div>
            </li>
        </aura:iteration>
    </ul>
</div>


relRecordTiles.js

({
doInit : function(component, event, helper) {
    console.log("relRecordTiles is starting up...");

    //Pull values from component 
    //var currentID = component.get("v.currentID");
    //var objectName = component.get("v.objectName");
    //var lookupField = component.get("v.lookupField");
    //var field1 = component.get("v.field1");
    //var field2 = component.get("v.field2");
    //var field3 = component.get("v.field3");

    //call relRecordTilesController.getResults server side controller
    var action = component.get('c.getResults');

    //Set the variables for the server side controller
    action.setParams({
        currentID : component.get("v.currentID"),
        objectName : component.get("v.objectName"),
        lookupField : component.get("v.lookupField"),
        field1 : component.get("v.field1"),
        field2 : component.get("v.field2"),
        field3 : component.get("v.field3")
    });

    // Set up the callback
    action.setCallback(this, $A.getCallback(function (response) {
        var state = response.getState();
        var resultsToast = $A.get("e.force:showToast");
        if(state === "SUCCESS"){
            //if successful stores query results in serverResult
            component.set('v.serverResult', response.getReturnValue());
        } else if (state === "ERROR") {
            //otherwise write errors to console for debugging
            alert('Problem with connection. Please try again. Error Code: relRecordTiles.doInit.action.setCallback');
            resultsToast.setParams({
                "title": "Error",
                "message": "relRecordTiles failed to load due to: " + JSON.stringify(result.error)
            });
            resultsToast.fire();
            var errors = response.getError();
            console.error(errors);
        }
    }));

    $A.enqueueAction(action);
}            

})


relRecordTilesController.apxc

public class relRecordTilesController {
@AuraEnabled
public static List<tileWrapper> getResults(id currentID, string objectName, string lookupField, string field1, string field2, string field3) {
    System.debug('getResults starting...');

    //add in query fields if they are not null
    string queryfields;
    if(field1 != null){queryfields = ', ' +field1;}
    if(field2 != null){queryfields = queryfields+ ', ' +field2;}
    if(field3 != null){queryfields = queryfields+ ', ' +field3;}

    //build the string we will query
    string queryString = 'SELECT id, name' +queryfields+ ' FROM ' +objectName+ ' WHERE ' +lookupField+ '=' +currentID;

    //get the data into a list
    List<sObject> queryOutput = new List<sObject>();
    queryOutput = database.query(queryString);
    system.debug('queryOutput = ' + queryOutput);

    //Iterate over the list and put the values into a wrapper class defined below
    List<tileWrapper> returnList = new List<tileWrapper>();
    for(sObject s: queryOutput){
        tileWrapper tile = new tileWrapper();
        tile.recID = String.valueOf(s.id);
        tile.recName = String.valueOf(s.get('name'));
        if(String.valueOf(s.get(field1)) != null ){tile.field1 = String.valueOf(s.get(field1));}
        if(String.valueOf(s.get(field2)) != null ){tile.field2 = String.valueOf(s.get(field2));}
        if(String.valueOf(s.get(field3)) != null ){tile.field3 = String.valueOf(s.get(field3));}
        returnList.add(tile);
    }

    system.debug('returnList = ' + returnList);
    return returnList;        
}


public class tileWrapper{
    public id recID{get;set;}
    public string recName{get;set;}
    public string field1{get;set;}
    public string field2{get;set;}
    public string field3{get;set;}
}

}


Calling component from parent Component

                    <lightning:formattedText value="Related Divisions" />
                    <c:relRecordTiles currentID="{!v.selItem}"
                                      objectName="Division2Contact__c"
                                      lookupField="Contact__c"
                                      field1="Full_Division_Name_Backward__c"
                                      field1Label="Division"
                                      field2="Division_Campus__c"
                                      field2Label="Campus"
                                      field3="Status__c"
                                      field3Label="Status"
                                      />
  • 3
    It doesn't look like you ever define a var result in your relRecordTiles.js, but in your error handling, you try to call JSON.stringify(result.error), without a variable for result. Did you mean response.error? – battery.cord May 1 '18 at 14:56
  • Also avoid asking multiple questions, ie, "How do I iterate over x" and "What variable is not defined" are two separate questions and would be better answered separately. – battery.cord May 1 '18 at 14:58
  • Well, @battery.cord, that helped a little bit. Now I get the error relRecordTiles failed to load due to: undefined which is better, but still not functioning. – Chance May 1 '18 at 15:19
  • Try debugging the rest of the variable, if your state == 'ERROR', then its not null, and clearly failed somewhere. Im not really versed in lightning otherwise I'd have posted an answer by now, hopefully at least this helps. – battery.cord May 1 '18 at 15:21
3

I recommend using the Developer Console to look at the apex debug logs when encountering errors with your apex actions in lightning.

In this particular instance I believe that you are receiving an error with your query at this line of your apex controller:

string queryString = 'SELECT id, name' +queryfields+ ' FROM ' +objectName+ ' WHERE ' +lookupField+ '=' +currentID;

The issue is with your WHERE clause. The ID should be surrounded by single quotes, so it will look like this

string queryString = 'SELECT id' +queryfields+ ' FROM ' +objectName+ ' WHERE ' +lookupField+ '=\'' +currentID+'\'';

In addition, as mentioned in the comments of your question, you are referencing result.error in your error toast code without ever declaring result as a variable. You most likely want to call response.getError() there instead, which is being passed into your callback function as a variable.

  • Bingo. I was about to post that I was having some kind of issue with the ID. First off, my reference needs to have currentID="{!v.selItem.val}" so it can actually pass the ID. THEN I was getting System.QueryException: unexpected token: 'D000003HiSUQA0' So I edited to your suggestion and the query works. Now my iterations are blank (but not null), but I can work on that a bit and see if I can figure it out. Thank you! – Chance May 1 '18 at 16:20

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.