+ Start a Discussion
Kishan Kumar 77Kishan Kumar 77 

Even after making changes to my code i am getting the same error. I need help with the onrowaction event handler and http callout. I am not sure where i am making mistake. Please help.

---------------------js file-----------------------------
import { LightningElement, track } from 'lwc';
import getOppList from '@salesforce/apex/customSearchController.getOppList';
import {ShowToastEvent} from 'lightning/platformShowToastEvent'
export default class CustomSearch extends LightningElement {
    @track opportunity;
    sVal='';
    receivedMessage;
    @track record = [];
    @track columns=[
        {label: 'Name', fieldName: 'Name',type: 'url', 
        typeAttributes: { 
            label: {
                fieldName: 'Name'
            } 
        },
        sortable: true },
          {label: 'Account Name', fieldName: 'AccountId',type: 'url', 
        typeAttributes: { 
            label: {
                fieldName: 'AccountId.Name'
            } 
        }, 
        sortable: true},
        {label: 'Stage Name', fieldName: 'StageName',type: 'picklist'},
        {label: 'Type', fieldName: 'Type',type: 'picklist'},
        {label: 'Amount', fieldName: 'Amount',type: 'currency'},
        {label:'Action',type:'button',typeAttributes: {
            label: 'Send Opp',
            name: 'Send',
            disabled: false,
            value: 'send',
            iconPosition: 'left'
        }
    }
    ];
    // update sVal var when input field value change
    updateSeachKey(event) {
        this.sVal = event.target.value;
    }
 
    // call apex method on button click 
    handleSearch() {
        // if search input value is not blank then call apex method, else display error msg 
        if (this.sVal !== '') {
            getOppList({
                    searchKey: this.sVal
                })
                .then(result => {
                    // set @track opportunities variable with return contact list from server  
                    this.opportunity = result;
                })
                .catch(error => {
                    // display server exception in toast msg 
                    const event = new ShowToastEvent({
                        title: 'Error',
                        variant: 'error',
                        message: error.body.message,
                    });
                    this.dispatchEvent(event);
                    // reset contacts var with null   
                    this.opportunity = null;
                });
        } else {
            // fire toast event if input field is blank
            const event = new ShowToastEvent({
                variant: 'error',
                message: 'Search text missing..',
            });
            this.dispatchEvent(event);
        }
    }
    handleRowAction(event){
        const row = event.detail.row;
        let actionName = event.detail.action.name;
        switch(actionName) {
            case 'Send':
            this.record = row;
            const calloutURI = 'https://herokuapp.com';
            fetch(calloutURI, {
                method: "POST",
                headers: {
                    "Accept": "application/json"
                  },
                  body:  JSON.stringify(record)
            })
            .then((response) => {
                       return response.json(); 
                })
                .then(responseJSON => {
                    console.log(responseJSON);
                    console.log(record);
                })
                .catch(error => {
                    const event = new ShowToastEvent({
                        title: 'Error',
                        variant: 'error',
                        message: error.body.message,
                    });
                    this.dispatchEvent(event);
                });
        }
    }
}
-------------------html file---------------------------
<template>
   <div class="slds-m-around_medium">
     
        <div class="slds-m-bottom_small">
            <lightning-input type="text"
               value={sVal}
               label="Search Opportunity"
               onchange={updateSeachKey}
               ></lightning-input>
         </div>
         
         <lightning-button label="Search"
            onclick={handleSearch}
            variant="brand"></lightning-button>
            
            <lightning-datatable data={opportunity} columns={columns} key-field="id" onrowaction={handleRowAction}>
            </lightning-datatable>
</div>This is the error i am getting and after making changes also it shows the same thing.
</template>
Alain CabonAlain Cabon
@Kishan Kumar

1) record seems an object (not an array)

2) Don't forget this.  each time you are using  this.record

3)  Callout from Lightning web components ( correct )
https://newstechnologystuff.com/2020/06/13/callout-from-lightning-web-components/

https://googlechrome.github.io/samples/fetch-api/fetch-post.html

But look at the console (chrome developer tools) because you need to declare the URL (https://herokuapp.com) as an exception for the CSP ( Content Security Policy ).

https://help.salesforce.com/articleView?id=csp_trusted_sites.htm&type=5 (https://help.salesforce.com/articleView?id=csp_trusted_sites.htm&type=5)
 
@track record = {};


handleRowAction(event) {
    const row = event.detail.row;
    let actionName = event.detail.action.name;
    console.log(">> action Name:" + actionName);
    console.log(">> row:" + JSON.stringify(row));
    switch (actionName) {
      case "Send":
        this.record = row;
        const calloutURI = "https://herokuapp.com";
        fetch(calloutURI, {
          method: "POST",
          headers: {
            Accept: "application/json"
          },
          body: JSON.stringify(this.record)
        })
          .then((response) => {
            return response.json();
          })
          .then((responseJSON) => {
            console.log(responseJSON);
            console.log(this.record);
          })
          .catch((error) => {
            const event = new ShowToastEvent({
              title: "Error",
              variant: "error",
              message: error.message
            });
            this.dispatchEvent(event);
          });
    }

 
Kishan Kumar 77Kishan Kumar 77
I am still getting the same error even after making the changes you suggested. If you could tell me what is wrong with the code it will be very helpful.
Alain CabonAlain Cabon
1) What is the code of your Apex controller ?   customSearchController.getOppLis

2) AccountId is correct but AccountId.Name is incorrect ( Account.Name ? )

   {label: 'Account Name', fieldName: 'AccountId',type: 'url', 
        typeAttributes: { 
            label: {
                fieldName: 'AccountId.Name'      //  Account.Name ? depends on the Apex controller.
            } 
        }, 
        sortable: true},
Kishan Kumar 77Kishan Kumar 77
-------------Custom Search Controller class-------------
public with sharing class customSearchController {
    
     @AuraEnabled(cacheable=true)
    public static list<Opportunity> getOppList(string searchKey){
      List<Opportunity> OppList=new List<Opportunity>();
        if(searchKey.isNumeric())
            {
                Decimal searchstringDouble = decimal.valueOf(searchKey);
                
                OppList = [select Id,Name,Account.Name,StageName,Type,Amount,CloseDate
                           
                           from Opportunity
                           
                           where Amount=:searchstringDouble];
                if(OppList.size() == 0){
            throw new AuraHandledException('No Record Found..'); 
         }
            }
         
        else{
             String newSearchText = searchKey+'%';
                
                OppList =[select Id,Name,Account.Name,StageName,Type,Amount,CloseDate
                          
                          from Opportunity
                          where Name like:newSearchText or Account.Name like:newSearchText
                          or StageName like:newSearchText or Type like:newSearchText];
            if(OppList.size() == 0){
            throw new AuraHandledException('No Record Found..'); 
         }
            
        }
        
     return OppList;   
    }
}



I have somehow managed to remove the error that I mentioned above. Now I have two problems :
1. I cannot display the Account name of the opportunity. It displays a URL instead of the name.

That is the error which is displayed in console.

2. The above error comes when I click on the Send button to make an HTTP callout.


 
Alain CabonAlain Cabon
Are you authorized for this call on Heroku?

 const calloutURI = "https://herokuapp.com";  (??)

I thought that was not your real URL (hidden) because that should be :   const calloutURI = 'https://foo.herokuapp.com/myaction';

https://trailhead.salesforce.com/fr/content/learn/modules/salesforce_heroku_integration/callouts_workflow_with_heroku
 
Alain CabonAlain Cabon
It seems that the direct call of Heroku doesn't work even when the CORS (setup > CORS) are changed.

The call via an Apex class is more sure.
Kishan Kumar 77Kishan Kumar 77
Is there any problem with the endpoint? Can you tell me to make the call from apex and use it in js?
Alain CabonAlain Cabon

Heroku from Apex (sure for Heroku, better option for a quick result):
https://trailhead.salesforce.com/en/content/learn/modules/apex_integration_services/apex_integration_rest_callouts

Fetch = GET (example) : A service component is an LWC - that should also work (but CORS error with Heroku).
https://developer.salesforce.com/blogs/2019/05/lightning-web-components-service-components.html

I tried a very simple Heroku call like you with a simple GET and I got the same CORS error each time (even if Setup > CORS (changed) ).

The REST Heroku call via an Apex class is sure but it is interesting to verify if a call from the front end (client) is also possible.

The documentaiton says that API call is not possible from the front end but the fetch above is also a service.

Heroku is CORS compatible by default ( I did'nt find a choice to change on the Heroku side).