Showing posts with label Lightning Out. Show all posts
Showing posts with label Lightning Out. Show all posts

Wednesday, March 11, 2020

Record Is Not Createable Issue In LWC

Most of the times you will receive this error when your using the base lightning components in your application.

Recently I got the same error while I'm using the <lightning-record-form > base component in one of the LWC component.My use case is just to display the record details basis on the given record id and with set of specified fields.

RecDetails.html

<template>
<lightning-record-form 
        mode="readonly" 
        columns="2" 
        object-api-name="WebSite_Details__c" 
        record-id={recId} 
        fields={objFields} >
        </lightning-record-form>
</template>

RecDetails.js

import { LightningElement,api,track,wire } from 'lwc';
import Lan_FIELD from '@salesforce/schema/WebSite_Details__c.Language__c';
import Site_FIELD from '@salesforce/schema/WebSite_Details__c.Site__c';
import Site_FIELD from '@salesforce/schema/WebSite_Details__c.Company__c';

export default class CallPopup extends NavigationMixin(LightningElement){
    @track objFields = [Site_FIELD, Site_FIELD,Lan_FIELD];
    @track recId;
 
//Wired Method Which Returns Record id
   @wire(fetchWebDet)
    wiredfetchWebDet({ error, data }) 
    {
         
        if (data) 
            {
 this.recId = data; // Dynamically assigns the record from the response
   
     }
 }
}

When I'm executing the component I was getting the same error Record Is Not Createable.
Then I started debugging the user related profile details and I figured out the user is not having an access to create a new record.

Interesting Point To Be Noted Here Is:

But still I'm not trying to create any new record,just trying to display the record which is already exist but it's internally trying to create a new record but logged in user is not having a create access on the specified object so it's failing.

If you look at the code I'm fetching the record id dynamically from wired method and assigning to it recId which is record Id in my case.So,here what is happening is the <lightning-record-form > will display the record details in view mode in case if record-id value is available if not then it will try to create a new record.

When the component got rendered this recId is not available so it's trying to create a new record that is why it's causing issue.

Solution:

Simple if condition which checks the whether record id is available would solves this problem.So,please invoke <lightning-record-form > if and only if record id is available.If record id is not available don't invoke the <lightning-record-form > .This solves the issue.Please find the update code below.

<template>
 <template if:true={recId}> //This if check solves your problem
  <lightning-record-form 
   mode="readonly" 
   columns="2" 
   object-api-name="WebSite_Details__c" 
   record-id={recId} 
   fields={objFields} >
  </lightning-record-form>
 </template>
</template>



Please comment or write us if you have any queries/requirements.

Please like,follow,bookmark,subscribe this site to receive daily updates.




Hope this helps you..Enjoy..!




Tuesday, February 18, 2020

How To Open (Url Format) Visual Force Page in Lightning Experience

If you want to open/preview the visual force page in salesforce lightning experience,do you know  how to construct the final url?if not ,this post will help you with the necessary details.

Url format in Classic:

   BaseUrl + '/apex/' + Your PageName +'?AnyQueryParams=xxx'

Url format in Lightning :

  BaseUrl + '/one/one.app#/alohaRedirect/apex/' + Your PageName +'?AnyQueryParams=xxx'

Let take an example your page name is call and your passing the mobile as query param.The complete your will be like below.
https://srinivas4sfdc--dev.lightning.force.com/one/one.app#/alohaRedirect/apex/Call?mobile=8884876772


Output:





Please comment or write us if you have any queries/requirements.

Please like,follow,bookmark,subscribe this site to receive daily updates.




Hope this helps you..Enjoy..!

Tuesday, December 31, 2019

How To Open Visual Force Page From LWC Components

Please use below code snippet to open the visual force page from LWC.

import { LightningElement,api,track,wire } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';

export default class CallPopup extends NavigationMixin(LightningElement)
{
    //Call this method from your .html file
 openVisualForcePage(event) 
 {

  const urlWithParameters = '/apex/YourVisualPageName?prop1=propval';
  console.log('urlWithParameters...'+urlWithParameters);
  this[NavigationMixin.Navigate]({
  type: 'standard__webPage',
  attributes: {
  url: urlWithParameters
  }
  }, false); //if you set true this will opens the new url in same window
 }
}

Note: The lightning-navigation works only in lightning experience and it will not work even if your using rendering your component in vf page (using lightning-out) in lightning experience or classic experience.

Hope this helps you..Enjoy..!

typeAttributes in lightning-datatable or lightning:datatable

Basically typeAttributes are the one of the major building blocks of <lightning-datatable>(in LWC) or <lightning:datatable> (in Aura).This will help us to format the data types /output display and attaching some of actions to your data displayed in table at each cell level ,row level or at the columns level.

The typeAttributes are attached to each columns data type when your specifying the columns for your data table in your java script file.

Each typeAttributes is having pre-defined set of attributes/properties basis on the data type of your column (your defining at the time of columns for table).

Usually each column definition will have below properties.

{ 
  label: 'Issue Type',  //Column Header Shown in Table
  fieldName: 'Issue_type__c', //Api name of filed 
  type:"text",   // tells text,date,url,email etc..
  initialWidth: 90 //column width
}

After attaching the typeAttributes the sample code looks like below.The sample code will create a column with name Case Number and Looks like a button ,on click of it you can fire rowAction automatically.


{
        label: 'Case Number',
        type: 'button',
        initialWidth: 90,
        typeAttributes: {
            iconName: 'action:preview',
            title: 'Preview',
            variant: 'border-filled',
            alternativeText: 'View',
            disabled: false,
            label: { fieldName: 'CaseNumber' }, // to assign the value dynamically
            name: { fieldName: 'Case_Age__c' }, // to assign the value dynamically
        }
    },

//other colums

At any time if you want to set any of the typeAttribute object attribute dynamically please use below syntax


  attributeName: { fieldName: 'api name of column/any other variable' }
          

As I have mentioned on the top each typeAttributes will have some set of properties based on the data type of your column.

If you want to know what are the available attributes for each datatype please refer below.




Sample Column Code With typeAttributes:


const datatableColums =[
 //Column 1 of type Url
    {
        label: 'Customer Name', fieldName: 'nameUrl', type: 'url',
        typeAttributes: {
            label: { fieldName: 'Name' },
            target: '_top'
        }
    },
 
 //Column 2 of type button 
 {
        label: 'PNR',
        type: 'button',
        initialWidth: 90,
        typeAttributes: {
            iconName: 'action:preview',
            title: 'Preview',
            variant: 'border-filled',
            alternativeText: 'View',
            disabled: false,
            label: { fieldName: 'Pnr__c' },
            name: { fieldName: 'Pnr__c' },

        }
    },
 
 //Column 3 of type date 
 {
        label: "Closed Date",
        fieldName: "ClosedDate",
        type: "date",
        typeAttributes:{
            weekday: "long",
            year: "numeric",
            month: "long",
            day: "2-digit"
        }
    }
]

Please watch this space more useful stuff.

Please follow,bookmark,subscribe this site to receive daily updates.

Facebook - https://www.facebook.com/ILoveCodingYou/?ref=bookmarks


Hope this helps you..Enjoy..!






Sunday, December 22, 2019

How To Select And Update Multiple Records Using LWC

If you have a requirement like to display the list of records related to particular record and then selection option to select one or many records from the display list and update the selected records.

And this entire functionality if you want to do using the LWC please follow the below steps and code.

Example :I'm building a component to display list of cases under a particular account and then I'm providing a button to user to make a call out to check which cases can be closed now.

As soon as I got a response from the api i will display all the cases which can be closed now with check box for selection and other cases with non selection option.

For generic demo purpose I'm assuming by default alternative cases are non-closable. So,to test this feature please select account with at least minimum 3 case records.



Apex Class- CaseFilterinLWCCntrl.cls

/**
 * (c) 2019 - srinivas4sfdc.com 
 *
 * Name           : CaseFilterinLWCCntrl
 * Created Date   : 22 Dec 2019
 * Created By     : Sreenivas M
 * Purpose        : Controller class for CaseFilterLWC component.
 *
 **/

global class CaseFilterinLWCCntrl
{
    
    public static List<Case> listCases{get;set;}  
    public static Id recId{get;set;}
    
    public CaseFilterinLWCCntrl(ApexPages.StandardController controller)
    {
        recId = controller.getId();
    }

    @AuraEnabled(cacheable=true)
    public static List<Case> fetchAllCases(String accntId)
    {
        listCases = new List<Case>();
        listCases = [Select id,casenumber,status,Origin,Subject,Type,ContactMobile FROM Case WHERE AccountId=:accntId limit 20];
        return listCases;
    }
 
 @AuraEnabled
    public static List<CasesWrapper> checkIsCloseableCases(List<Case> listAllCases)
    {
        
        System.debug('listAllCases...'+listAllCases);
        String errMsg ='';
        List<String> listCaseNum =new List<String>();
        List<String> listCloseableCaseNum =new List<String>();
        String respString = '{"cases":["';
        
        for(Integer i=0;i<listAllCases.size();i++)
        {
            listCaseNum.add(listAllCases[i].casenumber);
            if(Math.mod((i+1),2) == 0)
                listCloseableCaseNum.add(listAllCases[i].casenumber);
        
        }
        
        String finalCaseClose = String.join(listCloseableCaseNum,'","');
        respString = respString+finalCaseClose +'"]}';
       
        String jsonBody = '{"Country":"IND","casenumber":["'+finalCaseClose+'"]}';
        
        System.debug('respString ...'+respString +'...'+jsonBody);
        Http http = new Http();
        HttpResponse res = new HttpResponse();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('endPoint details..');
        req.setMethod('POST');
        req.setBody(jsonBody);
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('Currency', 'INR');
       
        try
        {
          //  res = http.send(req);                      
            string responseValue;// = res.getBody();           
         //   system.debug('responseValue-->>'+responseValue+''+res.getbody());
            responseValue = respString;           
         
                
            if(String.isNotBlank(responseValue)) //   if(res.getStatus()=='OK' && res.getStatusCode()==200 && String.isNotBlank(responseValue))
            {
                 map<string,object> IsCan = (map<string,object>)JSON.deserializeUntyped(responseValue);
                 List<CasesWrapper> listcaseWrap = new List<CasesWrapper>();
                 System.debug('responseValue...'+responseValue);
                 if(IsCan!=null && IsCan.containsKey('cases'))
                 {
                   List<String> closeableCsNum =new List<String>();
                   for(Object obj: (List<Object>)IsCan.get('cases'))
                       closeableCsNum.add((String)obj);
                   
                     System.debug('closeableCsNum...'+closeableCsNum);
                   for(Case cs : listAllCases)
                   {
                       if(closeableCsNum.contains(cs.casenumber))
                           listcaseWrap.add(new CasesWrapper(cs,true));
                       else
                            listcaseWrap.add(new CasesWrapper(cs,false));
                   }
                   
                   System.debug('listcaseWrap....'+listcaseWrap);
                   return listcaseWrap;
                 }
                 
                 else
                 {
                    errMsg ='Received invalid response';
                    throw new AuraHandledException(errMsg); 
                 }
            }
            else
            {
                    errMsg ='Oops something went wrong';
                    throw new AuraHandledException(errMsg); 
            }
        }
        
        Catch(Exception e)
        {
            System.debug('Exception ---'+errMsg);
            AuraHandledException ex = new AuraHandledException(errMsg);
            ex.setMessage(errMsg);
            throw ex;          
        }
    }
    
    @AuraEnabled
    public static string closeSelCases(List<String> listSelCasesToUpdate)
    {
        List<Case> listCasesToUpdate = new List<Case>();
        for(Case cs : [Select id,Status From Case WHERE CaseNumber IN :listSelCasesToUpdate])
        {
        //  cs.Status = 'Closed';
          listCasesToUpdate.add(cs);
        }
        
        try
        {
            if(!listCasesToUpdate.isEmpty())
            {
                update listCasesToUpdate;
                return 'Selected Cases Has Been Closed Successfully';
             }
         }
         Catch(Exception e)
         {
            AuraHandledException ex = new AuraHandledException(String.valueOf(e));
            ex.setMessage('An Error Occured While Closing The Cases');
            throw ex; 
         }         
          
        return null;
    }
       
                    
    public class CasesWrapper
    {
        @AuraEnabled public Case cs{get;set;}
        @AuraEnabled public boolean isCloseable{get;set;}
        @AuraEnabled public Boolean isSelect{get;set;}
            
        public CasesWrapper(Case csObj,Boolean closeable)
        {
            this.cs = csObj;
            this.isCloseable = closeable;
            this.isSelect = false;
        }

    }
 }

updateListOfCases.js (Java script controller of LWC):


/* eslint-disable no-script-url */
/* eslint-disable no-undef */
/* eslint-disable vars-on-top */
/* eslint-disable no-console */
/* eslint-disable no-unused-vars */
import { LightningElement, api, track, wire } from "lwc";
import fetchCases from "@salesforce/apex/CaseFilterinLWCCntrl.fetchAllCases";
import checkIsCloseableStatus from "@salesforce/apex/CaseFilterinLWCCntrl.checkIsCloseableCases";
import closelSelected from "@salesforce/apex/CaseFilterinLWCCntrl.closeSelCases";

const allCasescolumns = [
    {
        label: 'Case Number', fieldName: 'nameUrl', type: 'url',
        typeAttributes: {
            label: { fieldName: 'CaseNumber' },
            target: '_top'
        }
    },
    { label: 'Status', fieldName: 'Status' },
    { label: 'Origin', fieldName: 'Origin' },
    { label: 'Subject', fieldName: 'Subject' },
    { label: 'Type', fieldName: 'Type' },
    { label: 'ContactMobile', fieldName: 'ContactMobile', type: 'text' }

];

export default class UpdateListOfCases extends LightningElement {
    @api recordId;
    @track listAllCases;
    @track listAllCloseableCasesData;
    @track listcancelSeltedCases = [];
    @track columns = allCasescolumns;
    @track showDefTable;
    @track showIsCloseableBtn;
    @track showConfirmClosebtn;
    @track totalNoOfCases;
    @track showErrMsg;
    @track notifType;
    @track notifMsg;
    @track isLoading;

    @wire(fetchCases, { accntId: '$recordId'})
    wiredFetchCasesList({ error, data }) {
        if (data) {
            this.showIsCloseableBtn = true;
            this.listAllCases = data.map(record => Object.assign(
                { "nameUrl": '/console#%2F' + record.Id },
                record));

            this.totalNoOfCases = this.listAllCases.length;
            this.showDefTable = true;
        }
        else if (error) {
            this.error = error;
            this.listAllCases = undefined;
            this.showIsCloseableBtn = false;
        }
    }

    checkIsCloseableCasesJs(event) {
        this.isLoading = true;
        this.showDefTable = false;
        this.showIsCloseableBtn = true;
        this.showErrMsg = false;
        console.log('this.listAllCases....' + this.listAllCases);
        checkIsCloseableStatus({ listAllCases: this.listAllCases })
            .then(result => {
                this.listAllCloseableCasesData = result;
                this.showIsCloseableBtn = false;
                this.showConfirmClosebtn = false;
                this.isLoading = false;

            })
            .catch(error => {

                var errorMsg;
                if (Array.isArray(error.body)) {
                    this.errorMsg = error.body.map(e => e.message).join(', ');
                } else if (typeof error.body.message === 'string') {
                    this.errorMsg = error.body.message;
                }
                console.log('proper error--->' + this.errorMsg);
                this.isLoading = false;
                this.showErrMsg = true;
                this.notifType = 'error'; 
                this.notifMsg = this.errorMsg;
            });

    }

    rowSelChangeEvent(event) {
        this.showConfirmClosebtn = false;
        this.listAllCloseableCasesData.forEach(element => {
            if (element.cs.CaseNumber === event.currentTarget.dataset.id) {
                element.isSelect = event.target.checked;
            }

        });

        for (let i = 0; i < this.listAllCloseableCasesData.length; i++) {

            if (this.listAllCloseableCasesData[i].isSelect) {
                this.listcancelSeltedCases.push(this.listAllCloseableCasesData[i].cs.CaseNumber);
                this.showConfirmClosebtn = true;
            }

        }

    }

    selectDeselectAll(event) {
        if (event.target.checked) {
            this.listAllCloseableCasesData.forEach(element => {
                if (element.isCloseable) {
                    element.isSelect = true;
                    this.showConfirmClosebtn = true;
                }

            });
        }
        else {
            this.listAllCloseableCasesData.forEach(element => {
                if (element.isCloseable) {
                    element.isSelect = false;
                }
                this.showConfirmClosebtn = false;
            });
        }

    }

    closelselectedCaseJs(event) {
        this.isLoading = true;
        this.showErrMsg = false;
        this.listcancelSeltedCases = [];

        for (let i = 0; i < this.listAllCloseableCasesData.length; i++) {
            if (this.listAllCloseableCasesData[i].isSelect) {
                this.listcancelSeltedCases.push(this.listAllCloseableCasesData[i].cs.CaseNumber);
            }
        }


        closelSelected({ listSelCasesToUpdate: this.listcancelSeltedCases })
            .then(result => {
                console.log('cases--->' + result);
                this.showConfirmClosebtn = false;
                this.showErrMsg = true;
                this.notifType = 'success';
                this.notifMsg = result;
                this.isLoading = false;

            })
            .catch(error => {

                var errorMsg;
                if (Array.isArray(error.body)) {
                    this.errorMsg = error.body.map(e => e.message).join(', ');
                } else if (typeof error.body.message === 'string') {
                    this.errorMsg = error.body.message;
                }

                this.showConfirmClosebtn = true;
                this.showErrMsg = true;
                this.notifType = 'error';
                this.notifMsg = this.errorMsg;
                this.isLoading = false;

            });

    }

}

updateListOfCases.html

<template>
   <!-- To show the toast message in vf pages/classic enviornment-->
    <template if:true={showErrMsg}>
        <c-generic-toast-messages notificationtype={notifType} notificationmessage={notifMsg}></c-generic-toast-messages>
        <div class="slds-m-bottom_x-small"></div>
    </template>



    <template if:true={showDefTable}>
        <lightning-datatable data={listAllCases} columns={columns} key-field="id" hide-checkbox-column="true"></lightning-datatable>
    </template>


    <template if:true={listAllCloseableCasesData}>

        <div>
            <table class="slds-table slds-table_cell-buffer slds-table_bordered">
                <thead>
                    <tr>
                        <th>
                            <lightning-input type="checkbox" label="" onchange={selectDeselectAll} value={selAllChe}>
                            </lightning-input>
                        </th>
                        <th>Case Number</th>
                        <th>Status</th>
                        <th>Origin</th>
                        <th>Type</th>
                        <th>Subject</th>
                        <th>ContactMobile</th>
                        <th>Can Close?</th>
                    </tr>
                </thead>
                <tbody>
                    <template for:each={listAllCloseableCasesData} for:item="aItem">
                        <tr key={aItem.cs.CaseNumber}>
                            <td>
                                <template if:true={aItem.isCloseable} class="slds-text-align--left">
                                    <lightning-input type="checkbox" data-id={aItem.cs.CaseNumber} label="" value={aItem.isSelect} checked={aItem.isSelect} onchange={rowSelChangeEvent} ></lightning-input>
                                    <span class="slds-checkbox--faux"></span>
                                    <span class="slds-form-element__label text"></span>
                                </template>
                                <template if:false={aItem.isCloseable}>
                                    <lightning-icon icon-name="utility:error" alternative-text="Can't Close" variant="error" size="x-small" style="padding:0.1rem !important;"></lightning-icon></span>
                                </template>

                            </td>
                            <td >{aItem.cs.CaseNumber}-{aItem.isCloseable}</td>
                            <td >{aItem.cs.Status}</td>
                            <td>{aItem.cs.Origin}</td>
                            <td>{aItem.cs.Type}</td>
                            <td>{aItem.cs.Subject}</td>
                            <td>{aItem.cs.ContactMobile}</td>                          
                            <td class="slds-text-align--center">
                                <template if:true={aItem.isCloseable}>
                                    <lightning-icon icon-name="action:approval" alternative-text="Closeable" size="xx-small" style="padding:0.1rem !important;"></lightning-icon>
                                </template>
                                <template if:false={aItem.isCloseable}>
                                    <lightning-icon icon-name="utility:error" alternative-text="Non-Cancellable" variant="error" size="small" style="padding:0.1rem !important;"></lightning-icon>
                                </template>
                            </td>
                          
                        </tr>
                    </template>

                </tbody>

            </table>
        </div>
    </template>
    <template if:true={showIsCloseableBtn} class="slds-is-relative">
        <lightning-button label="Check Closeable Cases" title="Check Closeable Cases" variant="success" onclick={checkIsCloseableCasesJs} class="slds-align_absolute-center slds-m-top_medium slds-size_small"></lightning-button>

        <div if:true={isLoading}>
            <lightning-spinner alternative-text="Loading..." variant="brand" size="large" class="slds-is-absolute"></lightning-spinner>
        </div>
    </template>


    <template if:true={showConfirmClosebtn} class="slds-is-relative">
        <lightning-button label="Close Selected" title="Close Selected" variant="success" onclick={closelselectedCaseJs} class="slds-align_absolute-center slds-m-top_medium"></lightning-button>
        <div if:true={isLoading}>
            <lightning-spinner alternative-text="Loading..." variant="brand" size="large" class="slds-is-absolute"></lightning-spinner>
        </div>
    </template>

    <template if:false={listAllCases}>
        No Cases Found For This Account.
    </template>
</template>

updateListOfCases.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="updateListOfCases">
    <apiVersion>46.0</apiVersion>
    <isExposed>true</isExposed>
     <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

After deploying all these changes we are ready to go demo and below is the sample demo how this code works.


Please keep below points as notes while developing the same.
  • { "nameUrl": '/console#%2F' + record.Id } - This is to open a record in classic console using lightning out
  • <c-generic-toast-messages> - Custom component used to show toast messages in classic environment,in case of lightning we can directly use toast messages.
For more update please like/follow this page on

Hope this helps you..Enjoy..!