function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Jugbeer BholaJugbeer Bhola 

SOQL List with different criteria until list is full

The user is asking for data to be displayed based on 4 different criteria types fo the same sObject type.  The list should display a maximum of 6 records.  If the first 4 records queried match the criteria then collect and show the 4 records of data. Continue to search for more data until the number of 6 records are collected.  If only 1 record for the next set of criteria matches then collect that 1 record and add it for a total of 5 records, We still will need 1 more record so another query needs to happen with different criteria until the list is full.  How can this be done?
Best Answer chosen by Jugbeer Bhola
Jugbeer BholaJugbeer Bhola
Thanks for replying.  That was a good idea but a different direction was needed.  A wrapper class was used for sorting and a generic list created to handle the fusion of two objects.   Here is the wrapper class, the component controller and the component in case someone is wondering.
public class CustomerProductWrapper implements Comparable {
         
    @AuraEnabled
    public String ProductID {get; set;}
    @AuraEnabled
    public String ProductNumber {get; set;}
    @AuraEnabled
    public String ProductType {get; set;}
    @AuraEnabled
    public String ProductStatus {get; set;}
    @AuraEnabled
    public Decimal ProductValue {get; set;}
    @AuraEnabled
    public String ProductURL {get; set;}
    @AuraEnabled
    public Date ProductEffectiveDate {get; set;}
    /*
* Generic constructor
*/
    public CustomerProductWrapper() {}
    /**
* The Sort Method
*/        
    public Integer compareTo(Object compareTo) {        
        
        Boolean ascending = false;
        CustomerProductWrapper Product = (CustomerProductWrapper)compareTo;   
        if (this.ProductEffectiveDate > Product.ProductEffectiveDate) {
            return ascending ? 1 : -1;
        } else if(this.ProductEffectiveDate < Product.ProductEffectiveDate) {
            return ascending ? -1 : 1;
        } else {
            return 0;
        }       
    }    
}
public without sharing class CustomerProduct_CX {
    static List<CustomerProductWrapper> ProductWrapperForPageDisplay = new List<CustomerProductWrapper>();  
    static List<CustomerProductWrapper> ProductWrapperForInternalUse = new List<CustomerProductWrapper>();  
    public Account theCustomer;
    public static Set<Id> thePolicySet = new Set<Id>();
    public static Set<Id> theMasterPolicySet = new Set<Id>();
    static Integer theCounter = 0;
    public static Integer theLimit = 4; 
    
    public CustomerProduct_CX(ApexPages.StandardController controller){        
        this.theCustomer = (Account)controller.getRecord();      
    }
    
    @AuraEnabled
    public static String getUITheme(){
        return UserInfo.getUiThemeDisplayed();
    }
    
    @AuraEnabled
    public static List<CustomerProductWrapper> getCustomerProducts(String customerId){        
        //Generic List with both the Policy Relationship and Policy data blended. 
        //Data will be loaded into the list ordered by Issue Open Date.  This signification will allow for
        //the partial compliance of the first three hierarcy specifications.  
        List<sObject> GenericPoliciesList = new List<sObject>();
        GenericPoliciesList = [SELECT Id, PolicyId__c, Role__c, PolicyId__r.StatusEffectiveDate__c, PolicyId__r.PolicyTypeDscr__c, PolicyId__r.Name, PolicyId__r.IssueOpenDate__c,  PolicyId__r.FaceAmt__c, PolicyId__r.ContractStatusCode__c FROM PolicyRelationship__c WHERE AccountId__c =: customerId AND IssueOpenDate__c <> null Order By IssueOpenDate__c ];
        theMasterPolicySet.clear();
        //Hierarchy 1     
        //Retrieve Policies with an Active Status and an Owner/Controller Role.  Display them in Issue Open Date order. 
        for(SObject SinglePolicyIteration1:  GenericPoliciesList){
            If ( theMasterPolicySet.size() < theLimit ){                
                if(String.valueof(SinglePolicyIteration1.get('Role__c')) ==  'Owner/Controller' && 
                   String.valueof(SinglePolicyIteration1.getSObject('PolicyId__r').get('ContractStatusCode__c')) == 'Active'){
                       loadWrapperForActive(SinglePolicyIteration1);                
                   }
            }
            else{
                //If the Master Policy Set has reached a size of four get out and display the records.
                return ProductWrapperForPageDisplay;
            }
        }
        
        //Hierarchy 2
        //Retrieve Policies with an Active Status and an Issue on/Open for Role.  Display them in Issue Open Date order. 
        for(SObject SinglePolicyIteration2 :  GenericPoliciesList){
            If ( theMasterPolicySet.size() < theLimit ){                
                if(String.valueof(SinglePolicyIteration2.get('Role__c')) ==  'Issue on/Open for' && 
                   String.valueof(SinglePolicyIteration2.getSObject('PolicyId__r').get('ContractStatusCode__c')) == 'Active'){
                       loadWrapperForActive(SinglePolicyIteration2); 
                   }                    
            }
            else{
                //If the Master Policy Set has reached a size of four get out and display the records.
                return ProductWrapperForPageDisplay;
            }
        }
        
        //Hierarchy 3
        //Retrieve Policies with an Active Status and any Role.  Display them in Issue Open Date order.
        for(SObject SinglePolicyIteration3 :  GenericPoliciesList){
            If ( theMasterPolicySet.size() < theLimit ){
                if(String.valueof(SinglePolicyIteration3.getSObject('PolicyId__r').get('ContractStatusCode__c')) == 'Active'){
                    loadWrapperForActive(SinglePolicyIteration3); 
                }                    
            }
            else{ 
                //If the Master Policy Set has reached a size of four get out and display the records.
                return ProductWrapperForPageDisplay;
            }
        }
        
        //Hierarchy 4
        //Retrieve Policies with any Status other than Active and any Role.  Display them in Effective Date order.
        for(SObject SinglePolicyIteration4 : GenericPoliciesList){
            if(String.valueof(SinglePolicyIteration4.getSObject('PolicyId__r').get('ContractStatusCode__c')) != 'Active'){
                loadWrapperForNonActive(SinglePolicyIteration4);   
            }  
        }   
        
        //Sort the entire list of transient objects and load what is allowable - Up to 4  
        ProductWrapperForInternalUse.sort();
        
        //The wrapper class contains a compareTo method which executes when the sort command is issued.
        //The previous values collected were queried by issue date.  They are in the proper order.
        //The non-active policies are required to be collected by effective date.
        //These records had to be handle separately.          
        
        for (Integer i = 0; i < ProductWrapperForInternalUse.size(); i++) { 
            If ( ProductWrapperForPageDisplay.size() < theLimit ){
                ProductWrapperForPageDisplay.add( ProductWrapperForInternalUse[i]);    
            }
        } 
        //If the Master Policy Set has not reached a size of four get out and display the records available.
        return ProductWrapperForPageDisplay;
    }    
    
    //Process the active status values collected and load them in a wrapper 
    public static void loadWrapperForActive(SObject thePolicy){
        CustomerProductWrapper ActiveProductWrapper = new CustomerProductWrapper();  
        //The purpose of the Master Policy Set is to ensure the same entry is not
        //displayed more than once.
        if (!theMasterPolicySet.contains(String.valueof(thePolicy.get('Id')))){           
            ActiveProductWrapper.ProductID = String.valueof(thePolicy.get('Id'));   
            ActiveProductWrapper.ProductNumber = String.valueof(thePolicy.getSObject('PolicyId__r').get('Name'));
            ActiveProductWrapper.ProductType = String.valueof(thePolicy.getSObject('PolicyId__r').get('PolicyTypeDscr__c'));
            ActiveProductWrapper.ProductStatus = String.valueof(thePolicy.getSObject('PolicyId__r').get('ContractStatusCode__c'));
            string theValue = string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c'));
            if (string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')) == Null){
                ActiveProductWrapper.ProductValue = 0.0;               
            }
            else
            {
                ActiveProductWrapper.ProductValue = Decimal.valueof(string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')));
            }       
            if (String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')) == Null){
                ActiveProductWrapper.ProductEffectiveDate = null;               
            }
            else
            {
                ActiveProductWrapper.ProductEffectiveDate  =  Date.valueOf(String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')));
            }  
            ActiveProductWrapper.ProductURL = String.valueof(thePolicy.get('PolicyId__c'));
            ProductWrapperForPageDisplay.add(ActiveProductWrapper);
            //Retain the policy number to ensure it is not processed again.
            theMasterPolicySet.add(String.valueof(thePolicy.get('Id')));       
        }        
    }
    
    //Process the active status values collected and load them in a wrapper 
    public static void loadWrapperForNonActive(SObject thePolicy){
        CustomerProductWrapper NonActiveProductWrapper = new CustomerProductWrapper();  
        //The purpose of the Master Policy Set is to ensure the same entry is not
        //displayed more than once. As long as it is checked here to make sure it does not
        //exist the process is good.  This is the final step. 
        if (!theMasterPolicySet.contains(String.valueof(thePolicy.get('Id')))){           
            NonActiveProductWrapper.ProductID = String.valueof(thePolicy.get('Id'));   
            NonActiveProductWrapper.ProductNumber = String.valueof(thePolicy.getSObject('PolicyId__r').get('Name'));
            NonActiveProductWrapper.ProductType = String.valueof(thePolicy.getSObject('PolicyId__r').get('PolicyTypeDscr__c'));
            NonActiveProductWrapper.ProductStatus = String.valueof(thePolicy.getSObject('PolicyId__r').get('ContractStatusCode__c'));
            string theValue = string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c'));
            if (string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')) == Null){
                NonActiveProductWrapper.ProductValue = 0.0;               
            }
            else
            {
                NonActiveProductWrapper.ProductValue = Decimal.valueof(string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')));
            }  
            if (String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')) == Null){
                NonActiveProductWrapper.ProductEffectiveDate = null;               
            }
            else
            {
                NonActiveProductWrapper.ProductEffectiveDate  =  Date.valueOf(String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')));
            }              
            NonActiveProductWrapper.ProductURL = String.valueof(thePolicy.get('PolicyId__c'));
            ProductWrapperForInternalUse.add(NonActiveProductWrapper);        
        }        
    }
}
<aura:component controller="CustomerProduct_CX">
    <!-- attributes -->
    <aura:attribute name="customerId" type="String"/>
    <aura:attribute name="customerProduct" type="CustomerProductWrapper[]" />
    <aura:attribute name="UITheme" type="String" />
    
    <!--Handlers -->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
    <div class="slds">
        <table class="slds-table slds-table--bordered slds-max-medium-table--stacked-horizontal slds-no-row-hover">
            <thead>
                <tr>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">CONTRACT ACCOUNT NUMBER</th>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">PLAN TYPE</th>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">STATUS</th>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">VALUE</th>                        
                </tr>
            </thead>
            <tbody>
                <aura:iteration items="{!v.customerProduct}" var="customerProd">
                    <tr class="slds-hint-parent">
                        <td class="slds-size--2-of-12" data-label="Name"><a id="{!'lookup' + customerProd.ProductURL + 'opp4'}" onblur="{!c.hideMini}" onfocus="{!c.showMini}" onmouseout="{!c.hideMini}" onmouseover="{!c.showMini}" onclick="{!c.navigateToURL}" class="bttns" data-value="{!customerProd.ProductURL}">{!customerProd.ProductNumber}</a></td>
                        <td class="slds-size--2-of-12" data-label="Plan Type">{!customerProd.ProductType}</td>
                        <td class="slds-size--2-of-12" data-label="Status">{!customerProd.ProductStatus}</td>
                        <td class="slds-size--2-of-12" data-label="Value">{!customerProd.ProductValue}</td>
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </div>
</aura:component>



 

All Answers

Rohit Sharma 66Rohit Sharma 66
Use dynamic SOQL query, where u can add the additional filter based on the list size.

Just try and let me know if it works.
 
Jugbeer BholaJugbeer Bhola
Thanks for replying.  That was a good idea but a different direction was needed.  A wrapper class was used for sorting and a generic list created to handle the fusion of two objects.   Here is the wrapper class, the component controller and the component in case someone is wondering.
public class CustomerProductWrapper implements Comparable {
         
    @AuraEnabled
    public String ProductID {get; set;}
    @AuraEnabled
    public String ProductNumber {get; set;}
    @AuraEnabled
    public String ProductType {get; set;}
    @AuraEnabled
    public String ProductStatus {get; set;}
    @AuraEnabled
    public Decimal ProductValue {get; set;}
    @AuraEnabled
    public String ProductURL {get; set;}
    @AuraEnabled
    public Date ProductEffectiveDate {get; set;}
    /*
* Generic constructor
*/
    public CustomerProductWrapper() {}
    /**
* The Sort Method
*/        
    public Integer compareTo(Object compareTo) {        
        
        Boolean ascending = false;
        CustomerProductWrapper Product = (CustomerProductWrapper)compareTo;   
        if (this.ProductEffectiveDate > Product.ProductEffectiveDate) {
            return ascending ? 1 : -1;
        } else if(this.ProductEffectiveDate < Product.ProductEffectiveDate) {
            return ascending ? -1 : 1;
        } else {
            return 0;
        }       
    }    
}
public without sharing class CustomerProduct_CX {
    static List<CustomerProductWrapper> ProductWrapperForPageDisplay = new List<CustomerProductWrapper>();  
    static List<CustomerProductWrapper> ProductWrapperForInternalUse = new List<CustomerProductWrapper>();  
    public Account theCustomer;
    public static Set<Id> thePolicySet = new Set<Id>();
    public static Set<Id> theMasterPolicySet = new Set<Id>();
    static Integer theCounter = 0;
    public static Integer theLimit = 4; 
    
    public CustomerProduct_CX(ApexPages.StandardController controller){        
        this.theCustomer = (Account)controller.getRecord();      
    }
    
    @AuraEnabled
    public static String getUITheme(){
        return UserInfo.getUiThemeDisplayed();
    }
    
    @AuraEnabled
    public static List<CustomerProductWrapper> getCustomerProducts(String customerId){        
        //Generic List with both the Policy Relationship and Policy data blended. 
        //Data will be loaded into the list ordered by Issue Open Date.  This signification will allow for
        //the partial compliance of the first three hierarcy specifications.  
        List<sObject> GenericPoliciesList = new List<sObject>();
        GenericPoliciesList = [SELECT Id, PolicyId__c, Role__c, PolicyId__r.StatusEffectiveDate__c, PolicyId__r.PolicyTypeDscr__c, PolicyId__r.Name, PolicyId__r.IssueOpenDate__c,  PolicyId__r.FaceAmt__c, PolicyId__r.ContractStatusCode__c FROM PolicyRelationship__c WHERE AccountId__c =: customerId AND IssueOpenDate__c <> null Order By IssueOpenDate__c ];
        theMasterPolicySet.clear();
        //Hierarchy 1     
        //Retrieve Policies with an Active Status and an Owner/Controller Role.  Display them in Issue Open Date order. 
        for(SObject SinglePolicyIteration1:  GenericPoliciesList){
            If ( theMasterPolicySet.size() < theLimit ){                
                if(String.valueof(SinglePolicyIteration1.get('Role__c')) ==  'Owner/Controller' && 
                   String.valueof(SinglePolicyIteration1.getSObject('PolicyId__r').get('ContractStatusCode__c')) == 'Active'){
                       loadWrapperForActive(SinglePolicyIteration1);                
                   }
            }
            else{
                //If the Master Policy Set has reached a size of four get out and display the records.
                return ProductWrapperForPageDisplay;
            }
        }
        
        //Hierarchy 2
        //Retrieve Policies with an Active Status and an Issue on/Open for Role.  Display them in Issue Open Date order. 
        for(SObject SinglePolicyIteration2 :  GenericPoliciesList){
            If ( theMasterPolicySet.size() < theLimit ){                
                if(String.valueof(SinglePolicyIteration2.get('Role__c')) ==  'Issue on/Open for' && 
                   String.valueof(SinglePolicyIteration2.getSObject('PolicyId__r').get('ContractStatusCode__c')) == 'Active'){
                       loadWrapperForActive(SinglePolicyIteration2); 
                   }                    
            }
            else{
                //If the Master Policy Set has reached a size of four get out and display the records.
                return ProductWrapperForPageDisplay;
            }
        }
        
        //Hierarchy 3
        //Retrieve Policies with an Active Status and any Role.  Display them in Issue Open Date order.
        for(SObject SinglePolicyIteration3 :  GenericPoliciesList){
            If ( theMasterPolicySet.size() < theLimit ){
                if(String.valueof(SinglePolicyIteration3.getSObject('PolicyId__r').get('ContractStatusCode__c')) == 'Active'){
                    loadWrapperForActive(SinglePolicyIteration3); 
                }                    
            }
            else{ 
                //If the Master Policy Set has reached a size of four get out and display the records.
                return ProductWrapperForPageDisplay;
            }
        }
        
        //Hierarchy 4
        //Retrieve Policies with any Status other than Active and any Role.  Display them in Effective Date order.
        for(SObject SinglePolicyIteration4 : GenericPoliciesList){
            if(String.valueof(SinglePolicyIteration4.getSObject('PolicyId__r').get('ContractStatusCode__c')) != 'Active'){
                loadWrapperForNonActive(SinglePolicyIteration4);   
            }  
        }   
        
        //Sort the entire list of transient objects and load what is allowable - Up to 4  
        ProductWrapperForInternalUse.sort();
        
        //The wrapper class contains a compareTo method which executes when the sort command is issued.
        //The previous values collected were queried by issue date.  They are in the proper order.
        //The non-active policies are required to be collected by effective date.
        //These records had to be handle separately.          
        
        for (Integer i = 0; i < ProductWrapperForInternalUse.size(); i++) { 
            If ( ProductWrapperForPageDisplay.size() < theLimit ){
                ProductWrapperForPageDisplay.add( ProductWrapperForInternalUse[i]);    
            }
        } 
        //If the Master Policy Set has not reached a size of four get out and display the records available.
        return ProductWrapperForPageDisplay;
    }    
    
    //Process the active status values collected and load them in a wrapper 
    public static void loadWrapperForActive(SObject thePolicy){
        CustomerProductWrapper ActiveProductWrapper = new CustomerProductWrapper();  
        //The purpose of the Master Policy Set is to ensure the same entry is not
        //displayed more than once.
        if (!theMasterPolicySet.contains(String.valueof(thePolicy.get('Id')))){           
            ActiveProductWrapper.ProductID = String.valueof(thePolicy.get('Id'));   
            ActiveProductWrapper.ProductNumber = String.valueof(thePolicy.getSObject('PolicyId__r').get('Name'));
            ActiveProductWrapper.ProductType = String.valueof(thePolicy.getSObject('PolicyId__r').get('PolicyTypeDscr__c'));
            ActiveProductWrapper.ProductStatus = String.valueof(thePolicy.getSObject('PolicyId__r').get('ContractStatusCode__c'));
            string theValue = string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c'));
            if (string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')) == Null){
                ActiveProductWrapper.ProductValue = 0.0;               
            }
            else
            {
                ActiveProductWrapper.ProductValue = Decimal.valueof(string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')));
            }       
            if (String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')) == Null){
                ActiveProductWrapper.ProductEffectiveDate = null;               
            }
            else
            {
                ActiveProductWrapper.ProductEffectiveDate  =  Date.valueOf(String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')));
            }  
            ActiveProductWrapper.ProductURL = String.valueof(thePolicy.get('PolicyId__c'));
            ProductWrapperForPageDisplay.add(ActiveProductWrapper);
            //Retain the policy number to ensure it is not processed again.
            theMasterPolicySet.add(String.valueof(thePolicy.get('Id')));       
        }        
    }
    
    //Process the active status values collected and load them in a wrapper 
    public static void loadWrapperForNonActive(SObject thePolicy){
        CustomerProductWrapper NonActiveProductWrapper = new CustomerProductWrapper();  
        //The purpose of the Master Policy Set is to ensure the same entry is not
        //displayed more than once. As long as it is checked here to make sure it does not
        //exist the process is good.  This is the final step. 
        if (!theMasterPolicySet.contains(String.valueof(thePolicy.get('Id')))){           
            NonActiveProductWrapper.ProductID = String.valueof(thePolicy.get('Id'));   
            NonActiveProductWrapper.ProductNumber = String.valueof(thePolicy.getSObject('PolicyId__r').get('Name'));
            NonActiveProductWrapper.ProductType = String.valueof(thePolicy.getSObject('PolicyId__r').get('PolicyTypeDscr__c'));
            NonActiveProductWrapper.ProductStatus = String.valueof(thePolicy.getSObject('PolicyId__r').get('ContractStatusCode__c'));
            string theValue = string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c'));
            if (string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')) == Null){
                NonActiveProductWrapper.ProductValue = 0.0;               
            }
            else
            {
                NonActiveProductWrapper.ProductValue = Decimal.valueof(string.valueof(thePolicy.getSObject('PolicyId__r').get('FaceAmt__c')));
            }  
            if (String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')) == Null){
                NonActiveProductWrapper.ProductEffectiveDate = null;               
            }
            else
            {
                NonActiveProductWrapper.ProductEffectiveDate  =  Date.valueOf(String.valueof(thePolicy.getSObject('PolicyId__r').get('StatusEffectiveDate__c')));
            }              
            NonActiveProductWrapper.ProductURL = String.valueof(thePolicy.get('PolicyId__c'));
            ProductWrapperForInternalUse.add(NonActiveProductWrapper);        
        }        
    }
}
<aura:component controller="CustomerProduct_CX">
    <!-- attributes -->
    <aura:attribute name="customerId" type="String"/>
    <aura:attribute name="customerProduct" type="CustomerProductWrapper[]" />
    <aura:attribute name="UITheme" type="String" />
    
    <!--Handlers -->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    
    <div class="slds">
        <table class="slds-table slds-table--bordered slds-max-medium-table--stacked-horizontal slds-no-row-hover">
            <thead>
                <tr>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">CONTRACT ACCOUNT NUMBER</th>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">PLAN TYPE</th>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">STATUS</th>
                    <th class="slds-text-heading--label slds-size--2-of-12" scope="col">VALUE</th>                        
                </tr>
            </thead>
            <tbody>
                <aura:iteration items="{!v.customerProduct}" var="customerProd">
                    <tr class="slds-hint-parent">
                        <td class="slds-size--2-of-12" data-label="Name"><a id="{!'lookup' + customerProd.ProductURL + 'opp4'}" onblur="{!c.hideMini}" onfocus="{!c.showMini}" onmouseout="{!c.hideMini}" onmouseover="{!c.showMini}" onclick="{!c.navigateToURL}" class="bttns" data-value="{!customerProd.ProductURL}">{!customerProd.ProductNumber}</a></td>
                        <td class="slds-size--2-of-12" data-label="Plan Type">{!customerProd.ProductType}</td>
                        <td class="slds-size--2-of-12" data-label="Status">{!customerProd.ProductStatus}</td>
                        <td class="slds-size--2-of-12" data-label="Value">{!customerProd.ProductValue}</td>
                    </tr>
                </aura:iteration>
            </tbody>
        </table>
    </div>
</aura:component>



 
This was selected as the best answer