0

I'm trying to build a search component with multiple search criteria which includes multiple fields and filter criteria for which I am sending an array of json. But I am stuck when I try to send the data from more than one row. When I search using criteria from a single row I get the json but when I add an additional row and click on search button I get the below error. Can someone help me resolve this issue so that multiple criteria can be sent? enter image description here

FilterComponent.cmp
<aura:component controller="SearchFilterController" Implements="force:appHostable,flexipage:availableForRecordHome,force:hasRecordId">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <aura:attribute name="prodWrapper" type="list"/>
    <aura:attribute type="Object" name="testAttribute" />
    <aura:attribute name="accountList" type="Account[]"/>
    <aura:attribute name="productFields" type="list"/>
    <aura:attribute name="criteriaType" type="list"/>
    <lightning:card>
        <div class="slds-m-around--xx-large">
            <div class="slds-float_right slds-p-bottom_small">
                <h1 class="slds-page-header__title">Add Row 
                    <lightning:buttonIcon iconName="utility:add"  size="large" variant="bare" alternativeText="Add" onclick="{!c.addRow}"/>
                </h1>
            </div>
            <div class="container-fluid">        
                <table class="slds-table slds-table_bordered slds-table_cell-buffer"> 
                    <thead>
                        <tr class="slds-text-title_caps">
                            <th scope="col">
                                <div class="slds-truncate">Sr. No</div>
                            </th>
                            <th scope="col">
                                <div class="slds-truncate" title="Field Name">Field Name</div>
                            </th>
                            <th scope="col">
                                <div class="slds-truncate" title="Criteria">Criteria</div>
                            </th>
                            <th scope="col">
                                <div class="slds-truncate" title="Value">Value</div>
                            </th>  

                            <th scope="col">
                                <div class="slds-truncate" title="Action">Action</div>
                            </th>
                        </tr>
                    </thead>   
                    <tbody>      
                        <aura:iteration items="{!v.prodWrapper}" var="acc" indexVar="index">
                            <!--{!v.prodWrapper.size} -->
                            <tr>
                                <td> 
                                    {!index + 1}
                                </td>
                                <td>
                                    <!--<lightning:input name="fieldName" type="text" maxlength="50" value="{!v.testAttribute.fieldNames}" />
                                -->
                                     <lightning:select aura:id="PicklistId" label="Select a field" name="fieldName" >
                                                <option value="" text="- None -" /> 
                                                <aura:iteration items="{!v.productFields}" var="field">
                                                    <option value="{!field}" text="{!field}" />  
                                                </aura:iteration>
                                            </lightning:select>
                                </td>
                                <td>
                                   <!-- <lightning:input name="criteria" type="string" maxlength="30" value="{!acc.criteriaType}" />
                                -->
                                    <lightning:select aura:id="PicklistId2" label="Select a criteria" name="criteria" >
                                                <option value="" text="- None -" /> 
                                                <aura:iteration items="{!v.criteriaType}" var="per">
                                                    <option value="{!per}" text="{!per}" />  
                                                </aura:iteration>
                                            </lightning:select>
                                </td>
                                <td>
                                    <lightning:input name="searchFieldValue" type="text" value="{!acc.searchStr}" />
                                </td>
   
                                <td>
                                    <a onclick="{!c.removeRecord}" data-record="{!index}">
                                        <lightning:icon iconName="utility:delete" size="small" alternativeText="Delete"/>
                                        <span class="slds-assistive-text">Delete</span>
                                    </a>
                                </td> 
                            </tr>
                        </aura:iteration>
                    </tbody>
                </table>
                <div class="slds-align_absolute-center slds-p-top_small">
                    <lightning:button variant="brand" label="Submit" title="Brand action" onclick="{!c.searchProducts}" />
                </div>
            </div>
        </div>
    </lightning:card>
</aura:component> 

JS Controller :
({  
    doInit:function(component, event, helper) {
        
        var action = component.get("c.displayFieldsAndCriteria");
            
        action.setCallback(this, function(response) {
                //get response status 
                var state = response.getState();
                if (state === "SUCCESS") {
                    //set empty account list
                   var respValue=JSON.parse(response.getReturnValue());
                    component.set("v.testAttribute",respValue);
                    //var testValue = component.set("v.testAttribute",response.getReturnValue());
                    var respVal =response.getReturnValue();
                    //console.log('respVal >>> '+respVal);
                    console.log('v.testAttribute value >>>>'+respValue);
                    console.log('criteriaType value >>>>'+respValue.criteriaType);
                    console.log('searchStr value >>>>'+respValue.searchStr);
                   // console.log('fieldNames value >>>>'+JSON.stringify(respValue.fieldNames));
                    //console.log('respValue.fieldNames typeof >>>> '+typeof(respValue.fieldNames));
                    var result=respValue.fieldNames;
                    console.log('result stringified >>>>>> '+result.typeof);
                    component.set("v.productFields",respValue.fieldNames);
                    component.set("v.criteriaType",respValue.criteriaType);
                    /*var criteriaTypeVar= component.get("v.criteriaType");
                    console.log('criteriaTypeVar >>>> '+criteriaTypeVar[0]);
                    var productFieldsVar= component.get("v.productFields");
                    console.log('productFields >>>> '+productFieldsVar);*/
                    alert('data received from class');
                }
            }); 
            $A.enqueueAction(action);

    },
    
    addRow: function(component, event, helper) {
        //get the List from component  
        var pwList = component.get("v.prodWrapper");
        
        //Add New criteria
        pwList.push({
            'fieldNames': '',
            'criteriaType': '',
            'searchStr': ''
        });
        component.set("v.prodWrapper", pwList);
    },
    
    removeRecord: function(component, event, helper) {

        var criteriaList = component.get("v.prodWrapper");

        var selectedItem = event.currentTarget;
        //Get the selected item index
        var index = selectedItem.dataset.record;
        criteriaList.splice(index, 1);
        component.set("v.prodWrapper", criteriaList);
    },
        
    searchProducts: function(component, event, helper) {  
       var a= component.get("v.prodWrapper");
        var fName=component.find("PicklistId").get("v.value");
        for(var i=0;i<a.length;i++){
            
                console.log('fName >>>>'+ fName);
                a[i].fieldNames=fName;
                console.log('a value >>>> '+JSON.stringify(a));
           
        }
         /*var b= component.find("PicklistId2").get("v.value");
            var c= component.find("PicklistId").get("v.value");*/
        // use compo.find.get for picklist fields and while setting parameters create a json string
        // send the created json string to server
          /*console.log('typeof c>> '+typeof(c) +' '+JSON.stringify(c));
        console.log('typeof b >> '+typeof(b) +' '+JSON.stringify(b));
       console.log('typeof a >> '+typeof(a) +' '+JSON.stringify(a));*/
        var action = component.get("c.generateQuery");
            action.setParams({
                "prodWrapList": JSON.stringify(component.get("v.prodWrapper"))
            });
        action.setCallback(this, function(response) {
                //get response status 
                var state = response.getState();
                if (state === "SUCCESS") {
                    //set empty account list
                    component.set("v.prodWrapper", []);
                    alert('data sent to generateQuery');
                }
            }); 
            $A.enqueueAction(action);
       
    }
})

Apex controller :
public class SearchFilterController {
    @AuraEnabled
    public static void saveAccountList(List<Account> accList) 
    {        
        Insert accList;
    }
    
    @AuraEnabled
    public static string displayFieldsAndCriteria() 
    {        
        productWrapper pw = new productWrapper();
        system.debug('pw >>>>> '+pw);
        
        return json.serialize(pw);
    }
    
    @AuraEnabled
    public static void generateQuery(String prodWrapList) 
    {        
        //system.debug('prodWrapList >>>> '+prodWrapList.tostring());
        system.debug('prodWrapList serialized >>>> '+json.serialize(prodWrapList));
        system.debug('Output >>>>> '+json.deserialize(prodWrapList, List<JSON2Apex>.class));
        List<JSON2Apex> jsList=(List<JSON2Apex>)json.deserialize(prodWrapList, List<JSON2Apex>.class);
        system.debug(' jsList >>> ' +jsList);
        
        for(JSON2Apex ja :jsList){
            system.debug('Field Name >>> '+ja.fieldNames +' criteriaType >>>> '+ja.criteriaType +' searchStr >>>>'+ja.searchStr);
            
        }
        /*list<String> queryParams=(list<String>)prodWrapList;
        List<productWrapper> lstWrapper = new List<productWrapper>();*/
        //system.debug('Output >>>>> '+(List<productWrapper>)System.JSON.deserializeStrict(prodWrapList, list<productWrapper>.Class));
        
        //lstWrapper.addAll((List<productWrapper>)prodWrapList);
        //JSON.deserializeUntyped((list<string>)prodWrapList); ---->FATAL_ERROR System.TypeException: Invalid conversion from runtime type List<ANY> to List<String>
        //JSON.deserialize(prodWrapList, lstWrapper); ----> doesn't work
        //system.debug('deserialized lst >>>> '+lstWrapper);
    }
    
    
    /*public static List<string> getFields(String selectedObject){
        List<String> reqFields = new List<String>();
        Map <String,Schema.SObjectType> gd = Schema.getGlobalDescribe();
        Schema.SObjectType sobjType = gd.get(selectedObject);
        Schema.DescribeSObjectResult r = sobjType.getDescribe();
        Map<String, Schema.SObjectField> MapofField = r.fields.getMap();
        
        for(String fieldName : MapofField.keySet()) {
            Schema.SObjectField field = MapofField.get(fieldName);
            Schema.DescribeFieldResult F = field.getDescribe();
            System.debug('field-->'+field);
            reqFields.add(field);
            //System.debug('F-->'+F.getType of field 
        }
        System.debug(reqFields);
        return reqFields;
    }*/
    
    public class JSON2Apex {//used to parse json data coming in AND TO BUILD THE QUERY

    public String fieldNames;
    public String criteriaType;
    public String searchStr;

    
    public List<JSON2Apex> parse(String json) {
        return (List<JSON2Apex>) System.JSON.deserialize(json, List<JSON2Apex>.class);
    }
}
    
        public class productWrapper{// this is used to bind and display elements on the screen
            @AuraEnabled
            public String searchStr{get; set;}
            @AuraEnabled
            //public Map<String,String> fieldNames{get; set;}
            public list<String> fieldNames{get; set;}
            @AuraEnabled
            public list<String> criteriaType{get; set;}
            
            public productWrapper(){
                searchStr='';
                fieldNames= new list<String>();
                criteriaType= new list<String>();
                criteriaType.add('equal to');
                criteriaType.add('greater than or equal to');
                criteriaType.add('lesser than or equal to');
                criteriaType.add('lesser than');
                criteriaType.add('greater than');
                criteriaType.add('contains');
                
                Map<String, Schema.SObjectField> schemaFieldMap = Schema.SObjectType.Product2.fields.getMap();
                //Map<String, Object> queriedFieldValues = new Map<String, Object>();
                for (String fieldName: schemaFieldMap.keySet()) {
                    try { 
                        //system.debug('fieldName >>>'+fieldName +' mystery >>>>'+schemaFieldMap.get(fieldName));
                        fieldNames.add(fieldName); 
                    } 
                    catch(Exception e){
                        
                    }
            }
        }
    }
}

1 Answer 1

0

SecureComponent#find returns one of three values: null, SecureComponent, or Array, so you have to check for that first.

let result = component.find(someAuraId);
result = result? $A.util.isArray(result)? result: [result]: [];

Where we first see if the value exists at all. If so, we check if the result is an array. If so, we effectively do nothing. Otherwise, if it's not an array, we make it an array. Finally, if result is null, we return an empty array. This simplifies our code later.

Once you have that, you can Array#map the data:

let values = result.map(cmp => cmp.get("v.value"));

Or whatever other transformations you need to make the data structure you're looking for.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .