tag:blogger.com,1999:blog-2381339773700506452024-03-28T17:03:56.463+05:30Salesforce StuffExploring Salesforce Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.comBlogger179125tag:blogger.com,1999:blog-238133977370050645.post-47938699168558943112024-03-01T17:41:00.000+05:302024-03-01T17:41:03.603+05:30Lifecycle Hooks in LWC (Lightning We components)<p> A lifecycle hook is a callback method which is called
automatically at a specific phase of a component lifecycle. These are managed
by LWC framework. These hooks get called at different phases like initialization
of components, when elements gets inserted in DOM or removed from DOM,
rendering of components based on property changes etc.</p><p class="MsoNormal"><o:p></o:p></p><p class="MsoNormal">Lets go through different lifecycle hooks:</p><p class="MsoNormal"><u><b>constructor()</b></u></p><p class="MsoNormal"><o:p></o:p></p><ul style="text-align: left;"><li>Whenever component is created, this function gets called.</li><li>This hook flows from parent to child, which means that it fires in the parent first.</li><li>As child element do not exist, you cannot access them.</li><li>Properties are mainly assigned to component after constructor() and before connectedCallback()</li><li>If you define constructor() callback then you should always
super() from constructor(). This is because every LWC component extends
LightningElement and since LightningElement has its own constructor, so we
should first invoke the parent constructor.</li></ul>
<div>
<pre>import { LightningElement } from 'lwc'
export default class ConstructorCallbackExample extends LightningElement{
constructor(){
super();
}
}</pre>
</div>
<p class="MsoNormal"><u><b><br /></b></u></p><p class="MsoNormal"><u><b>connectedCallback()</b></u></p><p class="MsoNormal"></p><ul style="text-align: left;"><li>When the element is inserted into a document, this function gets called.</li><li>This hook flows also from parent to child. So you can’t access child elements because they don’t exist yet.</li><li>Properties are assigned to component so this callback can be used to perform or fetch initial data set.</li><li>If you manipulate the elements means adding or removing element from component, then connectedCallback() will fire more than once. So always put some checks if you don’t want to run particular logic everytime.</li><li>connectedCallback() can be used to Subscribe and Unsubscribe from a Message Channel.</li></ul>
<div>
<pre>import { LightningElement } from 'lwc'
export default class ConnectedCallbackExample extends LightningElement{
connectedCallback(){
console.log('***connected callback is called');
}
}</pre>
</div>
<p class="MsoNormal"><b><u><br /></u></b></p><p class="MsoNormal"><b><u>renderedCallback()</u></b></p><p class="MsoNormal"></p><ul style="text-align: left;"><li>renderedCallback() gets called after every render of component. Whenever value of reactive component changes, component get rendered.</li><li>renderedCallback() is specific to LWC and it has no dependency in HTML custom elements specifications.</li><li>renderedCallback() flows from child to parent.</li><li>Remember, updating state of component can cause infinite loop. So don’t update a public property or field in renderedCallback(). If you perform changes to reactive attributes, guard them or they can trigger wasteful rerenders or an infinite rendering loop.</li><li>Also don’t update a wire adapter configuration object property in renderedCallback(). </li></ul><div><u><b><br /></b></u></div><div><u><b>disconnectedCallback()</b></u></div><div><ul style="text-align: left;"><li>Whenever an element is removed from DOM, then disconnectedCallback() is called.</li><li>This hook flows from parent to child.</li><li>Use disconnectedCallback() to clean up work done in the connectedCallback(), like purging caches or removing event listeners or unsubscribe from a message channel.</li></ul>
<div>
<div>
<pre>import { LightningElement } from 'lwc'
export default class disconnectedCallbackExample extends LightningElement{
disconnectedCallback(){
console.log('**** disconnectedCallback is called');
}
}</pre>
</div>
</div><div><br /></div>
<div><u><b>render()</b></u></div></div><div><ul style="text-align: left;"><li>If there is need to display different UI to end user based on some conditions, then we can have 2 different HTML files and decide which HTML file to render based on conditions.</li><li>Render() may be called before or after connectedCallback().</li><li>Imagine that you have a component that can be rendered in two different ways but you don’t want to mix the HTML in one file. Create multiple HTML files in the component bundle. Import them both and add a condition in the render() method to return the correct template depending on the component’s state.</li><li>Although it’s possible for a component to render multiple templates, it is recommended to use lwc:if|elseif|else directives to render nested templates conditionally instead.</li></ul>
<div>
<pre>import { LightningElement } from "lwc";
import templateOne from "./templateOne.html";
import templateTwo from "./templateTwo.html";
export default class MiscMultipleTemplates extends LightningElement {
showTemplateOne = true;
render() {
return this.showTemplateOne ? templateOne : templateTwo;
}
switchTemplate() {
this.showTemplateOne = !this.showTemplateOne;
}
}</pre>
</div>
</div><p></p><div><u><b><br /></b></u></div><div><u><b>errorCallback(error, stack)</b></u></div><div><ul style="text-align: left;"><li>The errorCallback(error, stack) hook is called when the component throws an error.</li><li>The error argument is a JavaScript native error object, and the stack argument is a string.</li><li>This method works like a JavaScript catch{} block for catching errors.</li><li>The errorCallback() is unique to Lightning Web Components. Implement it to create an error boundary component that captures errors in all the descendent components in its tree. It captures errors that occur in the descendant's lifecycle hooks or during an event handler declared in an HTML template. errorCallback() catches errors that occurs in the descendant components but not itself. You can code the error boundary component to log stack information and render an alternative view to tell users what happened and what to do next</li></ul>
<div>
<pre>import { LightningElement } from "lwc";
export default class ErrorCallbackExample extends LightningElement {
error;
stack;
errorCallback(error, stack) {
this.error = error;
}
}</pre>
</div>
</div><div><br /></div><div>Hope this will help!!</div><div><br /></div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com3tag:blogger.com,1999:blog-238133977370050645.post-33548239722627002442024-02-22T21:51:00.000+05:302024-02-22T21:51:05.861+05:30Communicate from Parent to Child Component in LWC<p>There are few scenarios where we need to pass property/values from parent component to child component in LWC. There are different ways to achieve this:</p><p></p><ul style="text-align: left;"><li><b><u>Using @api decorator (public property)</u></b></li></ul><p></p><p class="MsoNormal">The @api decorator in the child component makes property as
public, which can be utilised by parent component to update it. So whenever you add child component in parent component, then specify child public property as an attribute and pass the value from parent component property. <o:p></o:p></p><p class="MsoNormal">For example, Child component contains public property "passedUrl" with @api decorator</p><p class="MsoNormal">-----------childComponent.html--------------------</p><p></p>
<div id="code1">
<pre><template>
<div style="background-color:#b2b689;border-style: solid;">
<b>Child component</b>
<p>URL passed from parent-<b>{passedUrl}</b></p>
</div>
</template></pre>
</div>
<p class="MsoNormal">--------childComponent.js---------------------</p>
<div id="code1">
<pre>import { LightningElement,api} from 'lwc';
export default class SkChildComponent extends LightningElement {
@api passedUrl;
}</pre>
</div>
<p class="MsoNormal">Now if you have to pass value to "passedUrl" property from parent component then just specify attribute as property name and pass any value from parent component property.</p><p class="MsoNormal">--------parentComponent.html---------------------</p>
<div id="code1">
<pre><template>
<lightning-card title="Communicate from Parent to Child">
<div style="background-color:#E6E6FA;border-style: ">
<b>This is parent Component</b>
<c-child-component passed-url={selResourceURL} >
</c-child-component>
</div>
</lightning-card>
</template></pre>
</div>
<p class="MsoNormal">--------parentComponent.js---------------------</p>
<div id="code1">
<pre>import { LightningElement,track } from 'lwc';
export default class SkParentContainerCmp extends LightningElement {
@track selResourceURL='https://www.sfdcstuff.com/';
}</pre>
</div>
<p><br /></p><p></p><ul style="text-align: left;"><li><b><u>Using getter setter property in child component</u></b></li></ul><div>you can define @api property with separate getter setter defined. Whenever the value of this property changes from parent component, your setter method for that property will always get called. Now you can define your custom logic if you have and then utilise that in child component.</div><p></p>
<p class="MsoNormal">--------childComponent.js---------------------</p>
<div id="code1">
<pre>import { LightningElement,api,track } from 'lwc';
export default class SkChildComponent extends LightningElement {
@track _userInputNumber;
@api
get userInputNumber(){
return this._userInputNumber;
}
set userInputNumber(value){
//write your logic to set any property
this._userInputNumber=value;
}
}</pre>
</div>
<p></p><ul style="text-align: left;"><li><b><u>By accessing child function from parent component</u></b></li></ul><div>You can decorate the function defined in child component with @api. Now parent component can access this public function. By using this method, you can invoke function defined in child component.</div><div><br /></div><div>Suppose you have defined below function in child component:</div><p></p>
<div id="code1">
<pre>@api
increaseCounter(){
//your logic
}</pre>
</div>
<p>Now from parent component you can access this function by using below syntax:</p><p>this.template.querySelector('c-child-component').increaseCounter();</p><p>I have created parent and child component to explain how this communication from parent to child component happen. Please find below complete code snippet and components snapshot:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijqhU7V0_0066_4EKAO3kXvEGptmIoAJ8NOWmFXbdVG578bSYuEWpfm69H7j7w3wOCms3vnybpno1pu_Pf_HiNqvpEc_Ohk2xcXG8onmysD0m1t8cCEO1ABLKFnokCO5ACoiU822rsgHfkYdcBeNHWG9y1HDKlVxo5_l7YF_Te6WPxE-RrZg7SyLnToII/s1226/image%201%20snapshot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="930" data-original-width="1226" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijqhU7V0_0066_4EKAO3kXvEGptmIoAJ8NOWmFXbdVG578bSYuEWpfm69H7j7w3wOCms3vnybpno1pu_Pf_HiNqvpEc_Ohk2xcXG8onmysD0m1t8cCEO1ABLKFnokCO5ACoiU822rsgHfkYdcBeNHWG9y1HDKlVxo5_l7YF_Te6WPxE-RrZg7SyLnToII/w400-h304/image%201%20snapshot.png" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Complete Code</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><script src="https://gist.github.com/Sunil02kumar/5d637f7d5162b15dd580d5504356f39a.js"></script></div><p>Hope this will Help!!</p>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com1tag:blogger.com,1999:blog-238133977370050645.post-36052931350584991442023-12-26T12:04:00.001+05:302023-12-26T12:04:35.070+05:30Export all Custom Metadata Records in CSV file using Apex<p>Using apex, we can export all custom metadata records in CSV files. This is sometime needed if we want to review all custom metadata records after sandbox refresh or to check the dependency of any field or attribute in all custom metadata records.</p><p><br /></p><p>Below is apex class which can be used for this and once you execute its method from developer console, you will receive email with csv that contain all custom metadata records.</p><p><script src="https://gist.github.com/Sunil02kumar/1c1060b4931d9c0f01b2a33d8c7c639e.js"></script></p><p>Open developer console and open execute anonymous window. Execute below script:</p><div style="text-align: left;"><span face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; color: #1f2328; white-space: pre;">SK_CustomMetadataUtility.</span><span face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; color: #1f2328; white-space: pre;">exportAllCMRecordsInCSV();</span></div><p><br /></p><p>Below is snapshot of csv file:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqgupERJ7pDgMsu_YOPY3x5XSQDlcF40aSExbucFHynO4A4DLt6vrI_q5Avh9xKqs2JSbBCHZ8TUKJ7piO6psWVZIdt8QnStuUpsSJOJSm7ldTBrLOCthN3qrNRwgNLu9E8SDvHQT6AIgtfzSHaM9QNG0Orc00ZfvQ1wGZ6TDZqUphAfTAw8VRoWGyS0A/s1346/custom%20metadata%20export%20snapshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="116" data-original-width="1346" height="35" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqgupERJ7pDgMsu_YOPY3x5XSQDlcF40aSExbucFHynO4A4DLt6vrI_q5Avh9xKqs2JSbBCHZ8TUKJ7piO6psWVZIdt8QnStuUpsSJOJSm7ldTBrLOCthN3qrNRwgNLu9E8SDvHQT6AIgtfzSHaM9QNG0Orc00ZfvQ1wGZ6TDZqUphAfTAw8VRoWGyS0A/w400-h35/custom%20metadata%20export%20snapshot.png" width="400" /></a></div><br /><p>Note:</p><p></p><ul style="text-align: left;"><li>This script will specify the custom metadata field api name and its value seperated by "&SK&" delimiter.</li><li>All fields and its values are seperated by comma.</li><li>You can modify this method to fetch all custom metadata related to installed packages by specifying a parameter for namespace.</li></ul><p></p><p><br /></p><p><span face="ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace" style="background-color: white; color: #1f2328; white-space: pre;">Hope this will help!!</span></p><p> </p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com6tag:blogger.com,1999:blog-238133977370050645.post-5635576069652115232023-08-20T13:52:00.003+05:302023-08-20T14:12:18.090+05:30Open Standard Email composer from LWC Component - Global Email Quick Action<p>As we all know that we can create Email Actions in Salesforce but capability to invoke Email Action from LWC components was not present. After Winter' 23, Salesforce allowed to invoke global email action from custom components (from Aura and LWC both).</p><p>In this blog, I am going to explain how to invoke email action from LWC component. You can launch email composer from custom button. </p><p>We have to use the lightning-navigation and lightning-page-reference-utils components to create a QuickAction (Global) Send Email action, which opens an email draft with pre-populated field values.</p><p>We will create simple LWC component which will have button. Once we click on this button, email composer will open. Below is sample code for reference:</p><script src="https://gist.github.com/Sunil02kumar/e1ecb0bb13f5a5b64f6f3798a70e4047.js"></script><p><br /></p><p>Note:</p><p></p><ul style="text-align: left;"><li>You can default email properties like subject, body, ccAddress, toAddress and fromEmailAddress.</li><li>You always need to provide record. Whenever you click on send button after composing email, system will create an emailmessage record with relatedToId as specified recordId.</li><li>encodeDefaultFieldValues is being provide to specify all default values.</li></ul><div><br /></div><div>Snapshots for reference:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixPN79927_KVm6iDDMQ6Z09fw1YID6h57pfLsrtui2Y_rFqhKZ4fGkD4KC8vugUzAmJYqkLuLcOSAghJR11oNchm6AmsH-XgmHlVEVK4WmhlyHJgbgyBpWZpLMypFKXuC1SfeCy5jcZOonUgOHJH3x6wyzefArVKpigCnj3PyMuGWEoKBfAxQDnCjEKmA/s1264/1.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="789" data-original-width="1264" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixPN79927_KVm6iDDMQ6Z09fw1YID6h57pfLsrtui2Y_rFqhKZ4fGkD4KC8vugUzAmJYqkLuLcOSAghJR11oNchm6AmsH-XgmHlVEVK4WmhlyHJgbgyBpWZpLMypFKXuC1SfeCy5jcZOonUgOHJH3x6wyzefArVKpigCnj3PyMuGWEoKBfAxQDnCjEKmA/w400-h250/1.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2Ln_cp0IY1qn5etZeMizI5aCyz4H4clzyww4iWD5h8NDIzV0GeLW4wLg6tv3Nfh02h3Z_fQ18Oj4H1HePudVTKTsTrhYbOksf9BDA8rHm7qeFf5OZNInAVCj2LVSV0M5tHc8R43NKtgEbYJItaIDLYOlWOiQC7rIeluRmRDggfEwc9SdcR_ZA7veczcE/s1847/2.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1067" data-original-width="1847" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2Ln_cp0IY1qn5etZeMizI5aCyz4H4clzyww4iWD5h8NDIzV0GeLW4wLg6tv3Nfh02h3Z_fQ18Oj4H1HePudVTKTsTrhYbOksf9BDA8rHm7qeFf5OZNInAVCj2LVSV0M5tHc8R43NKtgEbYJItaIDLYOlWOiQC7rIeluRmRDggfEwc9SdcR_ZA7veczcE/w400-h231/2.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Reference- <a href="https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.use_quick_actions_email" target="_blank">Create an Email as a Quick Action</a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Hope this will help!!</div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><br /><div><br /></div><p></p><p><br /></p><p><br /></p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com8tag:blogger.com,1999:blog-238133977370050645.post-49836043012260297772023-08-03T15:55:00.001+05:302023-08-03T16:02:28.900+05:30Automatically Remove Special Characters from Filename while Uploading Files in Salesforce<p> As we all know that we can perform URL hack to download all files related to parent record from salesforce. We have observed that sometime downloaded file name is changed to contentversion recordId by salesforce instead of actual file name. </p><p>It is my observation that if file name contains special characters, then when we perform download All, file name is changed to "068xxxxxxxxxxxxxx.pdf".</p><p>I have added 2 files to account record for reference:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc-K2u9ATtWZiUOylR4UdmAj6eJbFmHd0raeB3awqSFOKk8fg7D6VgHsdAEf4_BtZGH-4Q1cdnYItHd6akU6kM39Mfvcu3Zww30BQ4lxBcJyucnJCn-YjTpCol0sgAD6nwOvFKJlGm3bbYz4lWxQxMQQ6cua_OePxPxW8MSCdWSQo3MAgDaMvZsUraX9w/s1612/Capture%20all%20files.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="334" data-original-width="1612" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgc-K2u9ATtWZiUOylR4UdmAj6eJbFmHd0raeB3awqSFOKk8fg7D6VgHsdAEf4_BtZGH-4Q1cdnYItHd6akU6kM39Mfvcu3Zww30BQ4lxBcJyucnJCn-YjTpCol0sgAD6nwOvFKJlGm3bbYz4lWxQxMQQ6cua_OePxPxW8MSCdWSQo3MAgDaMvZsUraX9w/w400-h83/Capture%20all%20files.PNG" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Now I can generate download URL if I have contentversionId of these 2 files. In my case the download URL will be:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">https://xxxx/sfc/servlet.shepherd/version/download/0680K00000kLSdbQAG/0680K00000kLSfwQAG</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">where xxxx is you org domain URL.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">You can use below script to generate download all files URL if you know the parent record Id.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><script src="https://gist.github.com/Sunil02kumar/b8358ef287d5637fda317a2b30aad242.js"></script></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">If I open this URL, I will zip file which will contain both files and when I will extract it, it will appear as shown below:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicYXAQhGGgcF0IAsDom0SC54rPq43NjnimYjswnvQZPhTsPNp0b1fpcP1v8KCEpBLklCkNKdco2YQZHV01z4tQP7AmnvoWC0k8VkM_nIQOUt2nWNJiF-wCgNXSbVe1r1cV7pMQr_M4j2c-oxE_sCB3Dk0R51zWf2XOdPGffkl7XuHFXg7_XvPe5792T4Q/s1413/downloaded%20files.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="278" data-original-width="1413" height="79" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicYXAQhGGgcF0IAsDom0SC54rPq43NjnimYjswnvQZPhTsPNp0b1fpcP1v8KCEpBLklCkNKdco2YQZHV01z4tQP7AmnvoWC0k8VkM_nIQOUt2nWNJiF-wCgNXSbVe1r1cV7pMQr_M4j2c-oxE_sCB3Dk0R51zWf2XOdPGffkl7XuHFXg7_XvPe5792T4Q/w400-h79/downloaded%20files.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">As my observation, if any special character is present in file name then salesforce changes the file name. If "-" character is present, then salesforce won't change file name.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">For this kind of scenarios, I recommend to have script in place which will remove all special characters from file name whenever file is being uploaded. You can write trigger on contentVersion object to remove special characters from file name. Below is code snippet which can help:</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><script src="https://gist.github.com/Sunil02kumar/eb56c3d80c93e68156330be600586b21.js"></script><div class="separator" style="clear: both; text-align: left;">Hope this will help!!!!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><br /><p><br /></p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com2tag:blogger.com,1999:blog-238133977370050645.post-45862531890426109372023-07-05T22:50:00.004+05:302023-07-05T22:51:42.742+05:30FieldDefinition - How to get list of all fields present in any Object using Tooling API in Salesforce<p>We can utilize Tooling API to get information of all fields present in a object. You can put different filters like to get all fields or specific fields like auto number fields, ExternalID fields etc.</p><p>Below is apex class which contains method to get all fields. Remember that callout uses Named Credential in order to do handshake with SFDC org.</p><p>This method contains 3 parameters:</p><ul style="text-align: left;"><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;">selOrgNCName : Name of Named Credential created to connect to SFDC org</li><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;">objAPIName : Specify the object API name in order to get list of all fields</li><li style="border: none; margin: 0px 0px 0.25em; padding: 0px;">namespacePrefix : Specify namespacePrefix if you want to retrieve fields related to any installed packages. If you want to get list of fields created in SFDC org, then specify blank or NULL.</li></ul><div><div>Note:</div><div><ul style="text-align: left;"><li>I have added filter not to return auto number fields. If you want to get those fields details then remove it from query string.</li><li>If you want to query only External Id fields then specify filter as DataType+Like+\'%25(External+ID)%25\'';</li></ul></div></div><div></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #333333;"><span style="font-size: 14.85px;"><br /></span></span></div><script src="https://gist.github.com/Sunil02kumar/a157b777ec32da88e25ee05c5ace271f.js"></script><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #333333;"><span style="font-size: 14.85px;"><br /></span></span></div><div><span face="Arial, Tahoma, Helvetica, FreeSans, sans-serif" style="color: #333333;"><span style="font-size: 14.85px;">Hope this will help!!</span></span></div><p><br /></p><p><br /></p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com3tag:blogger.com,1999:blog-238133977370050645.post-19774497332841068672023-07-04T21:25:00.003+05:302023-07-04T21:25:51.454+05:30EntityDefinition - How to get list of all objects present in any SFDC org using tooling API<p>Salesforce provide Metadata API through which we can metadata information present in any SFDC org. Metadata API is SOAP based which involves consuming WSDL and then calling methods provided in WSDL.</p><p>Salesforce has introduced Tooling API which is REST based and can be used to get metadata information from any salesforce org. Tooling API is very easy to implement.</p><p>EntityDefinition provides information about standard and custom metadata. Before invoking any Tooling API endpoint, we need to do handshake with SFDC org. You can utilise Oauth 2.0 (username-password flow) or create "Named Credential" for SFDC org from which you want to fetch information.</p><p><br /></p><p>Below is Apex class which contains method through which we can get all object details:</p><p>"findAllObjects" Method contains 3 parameters: </p><p></p><ul style="text-align: left;"><li>selOrgNCName : Name of Named Credential created to connect to SFDC org</li><li>namespacePrefix : Specify namespacePrefix if you want to retrieve objects related to any installed packages. If you want to get list of objects created in SFDC org, then specify blank or NULL.</li><li>objName : specify search string if you want to get list of specific objects that contain that string. Pass blank or NULL if you want to retrieve all objects.</li></ul><div><br /></div><p><script src="https://gist.github.com/Sunil02kumar/e75b3f63d16d3f5d55734e2d70230fbf.js"></script></p><br />Hope this will help!!Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com4tag:blogger.com,1999:blog-238133977370050645.post-83331078405567619962023-06-26T16:25:00.003+05:302023-06-26T20:04:53.874+05:30Composite Batch- Way to call multiple REST API in single request (sending multiple request to Salesforce)<p>Composite batch allows to send up to 25 separate API request in a single call to salesforce. Best thing about this is that all sub-request are considered as separate call. Suppose you want to move multiple records to next salesforce org or want to create multiple records in salesforce from external system then this will help you.</p><p><br /></p><p>By using composite batch API, I am going to create a new Account record, Update existing Account record (by using external Id field -Account_Unique_Id__c) and query account record in same API call.</p><p>Below are details you need:</p><p><u>REST API service URI-</u> /services/data/v56.0/composite/batch/</p><p><u>Request Body Sample-</u></p><p><span style="font-size: x-small;">{</span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"batchRequests": [{</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"method": "POST",</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"url": "v56.0/sobjects/Account",</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"richInput": {</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"Name": "New Account using Composite Batch"</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>},</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>{</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"method": "PATCH",</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"url": "v56.0/sobjects/account/Account_Unique_Id__c/ACC-000033",</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"richInput": {</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"NumberOfEmployees": "2000",</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"Type": "Customer"</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}, {</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"method": "GET",</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>"url": "v56.0/query/?q=SELECT+name+from+Account+where+Account_Unique_Id__c='ACC-000033'"</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}</span></span></p><p><span style="white-space: normal;"><span style="font-size: x-small;"><span style="white-space: pre;"> </span>]</span></span></p><p><span style="font-size: x-small;">}</span></p><p><span style="font-size: x-small;"><br /></span></p><p><u>Response Body:</u></p><p><span style="font-size: x-small;">{</span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"hasErrors": false,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"results": [{</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"statusCode": 201,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"result": {</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"id": "0010K00002mziKJQAY",</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"success": true,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"errors": []</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}, {</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"statusCode": 200,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"result": {</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"id": "0010K00002PBQTyQAP",</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"success": true,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"errors": [],</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"created": false</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}, {</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"statusCode": 200,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"result": {</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"totalSize": 1,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"done": true,</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"records": [{</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"attributes": {</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"type": "Account",</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"url": "/services/data/v56.0/sobjects/Account/0010K00002PBQTyQAP"</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>},</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>"Name": "Sunil Test Account"</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}]</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}</span></span></p><p><span style="font-size: x-small;"><span style="white-space: normal;"><span style="white-space: pre;"> </span>}]</span></span></p><p><span style="font-size: x-small;"></span></p><p><span style="font-size: x-small;">}</span></p><p><br /></p><p><u><b>Important points to consider while using this:</b></u></p><p></p><ul style="text-align: left;"><li>The response bodies and HTTP statuses of the subrequests in the batch are returned in a single response body.</li><li>Each sub request counts against rate limits.</li><li>Each API request are considered as separate and you can not pass information between them.</li><li>If one API request get successfully completed from batch request, then it gets committed. If any subsequent request fails then previous request is not rollbacked automatically.</li><li>Batch request should complete in 10 minutes. If batch times out then the remaining sub requests aren’t executed</li></ul><div><br /></div><div>Hope this will help!!</div><p></p><p><br /></p><p><br /></p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com0tag:blogger.com,1999:blog-238133977370050645.post-23778895799850747812023-03-26T14:04:00.000+05:302023-03-26T14:04:14.497+05:30Custom Events in Lightning Web Components : Pass data from child component to parent component<p>In order to communicate from child component to parent component in LWC, we use custom events. Custom events helps in passing data from child components to parent component in containment hierarchy.</p><p>If you want to refer on how same thing can be achieved in Aura Components then refer below article:</p><p><a href="https://www.sfdcstuff.com/2018/08/component-events-way-to-communicate.html" target="_blank">Component Events: Way to Communicate Between Components in Containment Hierarchy</a><br /></p><p><br /></p><p>Lightning component can create and dispatch events in a component’s JavaScript class. To create an event, use the CustomEvent() constructor. To dispatch an event, call the EventTarget.dispatchEvent() method.</p><p>The CustomEvent() constructor needs one required parameter, which is a string indicating what event has been performed. You can define ant string as event name. While defining event name, follw below recommendation based on DOM event standard.</p><p></p><ul style="text-align: left;"><li>No uppercase letters</li><li>No spaces</li><li>Use underscores to separate words</li></ul><p></p><p><b><u>Steps involved in implementing custom events</u></b></p><p>1. Create custom event in child component and dispatch that event.</p><p style="text-align: left;"><span> </span>const newEvent = new CustomEvent("search");<br /><span> </span>this.dispatchEvent(newEvent);</p><p>2. Handle the event in parent component.</p><p>When you declare the child component in parent component, then use "on" event handler to execute logic whenever the event is fired. Suppose you event name which is dispateched from child component is "search", event handler name will be "onsearch".</p><c-sk-child-cmp onsearch={capturedEvent}></c-sk-child-cmp><br />capturedEvent(event) {<div><span> </span>console.log("**recieved event-->" + event);</div><div>}<p style="text-align: left;"><b><u>Custom events to inform what action is performed in child component</u></b></p><p style="text-align: left;">If you want to inform parent component about what has been clicked or operation performed in child component, then you can simply define custom event as mentioned below:</p><p style="text-align: left;"><template><br /><span> </span><lightning-button label="Edit" onclick={editAction}></lightning-button><br /><span> </span><lightning-button label="New" onclick={deleteAction}></lightning-button><br /></template><span style="white-space: pre;"> </span></p><p style="text-align: left;"> editAction() {<br /><span style="white-space: pre;"> </span>const newEvent = new CustomEvent("edit");<br /> this.dispatchEvent(newEvent);<br /> }<br /><br /><span> </span>deleteAction() {<br /><span style="white-space: pre;"> </span>const newEvent = new CustomEvent("delete");<br /> this.dispatchEvent(newEvent);<br /> }</p><p><br /></p><p><b><u>Custom events to pass data to parent component</u></b></p><p>If you want to pass data to parent component, then set a detail property in the CustomEvent constructor. </p><p>You can pass any record id or any data from child component in detail property.</p><p style="text-align: left;">@track selectedRecordId;</p><p style="text-align: left;">handleResponse(event) {<br /><span style="white-space: pre;"> </span>const answerEvent = new CustomEvent("search", { detail: this.selectedRecordId});<br /><span style="white-space: pre;"> </span>this.dispatchEvent(answerEvent);<br />}</p><p style="text-align: left;">Parent component can access detail property in order to read data passed from child component</p><p style="text-align: left;"> capturedEvent(event) {<br /><span> </span>console.log("**recieved event detail-->" + event.detail);<br /> }</p><p style="text-align: left;"><br /></p><p><b><u>Note:</u></b> There is no restriction on data type of detail property but is is recommended to pass only primitive data. JavaScript passes all data types by reference except for primitives. If a component includes an object in its detail property, any listener can mutate that object without the component’s knowledge. This is a bad thing! It’s a best practice either to send only primitives, or to copy data to a new object before adding it to the detail property. Copying the data to a new object ensures that you’re sending only the data you want, and that the receiver can’t mutate your data.</p><p>Lets try to understand custom events through simple example:</p><p>We will create a child component "skChildCmp" which will contain few buttons. Once user will click on one of the button, child component will pass resource URL based on button click to parent component and parent component will display that URL.</p><p>Below is snapshot for parent component:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgJjpSrRWESrHOqsVhgBuYgn03JJaB_cYz1dzdmxnBtYCKv8CPpiZPVV5rfa03tFUWKKu18w3kSFCnJzPSzb6NAbRQ8PAEi9WE5r9nW5m7WzS6JQ7RUyjOY3u6Adn-NxJh3rGYAnnsdGoyqv3A52fzjn-TqmGf2c86MfQeG9F_Yl8DPDJKXHWouT1K/s1389/snap%201.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="1389" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgJjpSrRWESrHOqsVhgBuYgn03JJaB_cYz1dzdmxnBtYCKv8CPpiZPVV5rfa03tFUWKKu18w3kSFCnJzPSzb6NAbRQ8PAEi9WE5r9nW5m7WzS6JQ7RUyjOY3u6Adn-NxJh3rGYAnnsdGoyqv3A52fzjn-TqmGf2c86MfQeG9F_Yl8DPDJKXHWouT1K/w400-h183/snap%201.PNG" width="400" /></a></div><br /><p>Now when user clicks on SFDCSTUFF BLOGS button, URL for that button will be appearing on parent component.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisbwl4uZuoWApip-Ljw6oGbOs55_7g_XZ2dBbb7g6OYBP4wnLSKfJ90BKpvdwpbiPx8Lwu4UpKfJdf52YJ50oCHR-7GSaodJLBWsK0_a1_9SiLJmPLu2PRNDCHWg-vlOiVrEtC0uiw4iMfdVH6NIA-9t9wk39Lv0jg2mL6uAgWRWljVFpFDyWB3CQl/s1389/snap%201.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="633" data-original-width="1389" height="183" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisbwl4uZuoWApip-Ljw6oGbOs55_7g_XZ2dBbb7g6OYBP4wnLSKfJ90BKpvdwpbiPx8Lwu4UpKfJdf52YJ50oCHR-7GSaodJLBWsK0_a1_9SiLJmPLu2PRNDCHWg-vlOiVrEtC0uiw4iMfdVH6NIA-9t9wk39Lv0jg2mL6uAgWRWljVFpFDyWB3CQl/w400-h183/snap%201.PNG" width="400" /></a></div><br /><p>If user clicks on TRAILHEAD button, then parent will display URL for that.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs_Pm3RnltCl7D3QDYK9TgVVAusk3Pd7OX6jb72qElHZgvHX6-syFjzzPxVg7wxAhohZvY_AGOSMuQ2g7AEPTeTmJwBr2779sQsN9S8DP0BhvkSpioZUDrKnDK7NFd1HYmJ53HwasMWCPVt7nhDnzJoPKEOqgB7p3ErRBKofqDkKSZ8eCRetBwXwTO/s1388/snap%203.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="622" data-original-width="1388" height="179" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs_Pm3RnltCl7D3QDYK9TgVVAusk3Pd7OX6jb72qElHZgvHX6-syFjzzPxVg7wxAhohZvY_AGOSMuQ2g7AEPTeTmJwBr2779sQsN9S8DP0BhvkSpioZUDrKnDK7NFd1HYmJ53HwasMWCPVt7nhDnzJoPKEOqgB7p3ErRBKofqDkKSZ8eCRetBwXwTO/w400-h179/snap%203.PNG" width="400" /></a></div><br /><p>Below is complete code snippet:</p><p><br /><script src="https://gist.github.com/Sunil02kumar/78bd61c5241d3bbde721a31e8fab563f.js"></script><br />Hope this will help!!</p></div>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com11tag:blogger.com,1999:blog-238133977370050645.post-33024850350392565292022-10-13T09:34:00.002+05:302022-10-13T09:34:49.176+05:30lightning-tree-grid - Account Hierarchy Using lightning-tree-grid in LWC<p> In this blog, I am going share a approach through which you can display account hierarchy using lightning tree grid. You can place this lightning component on account record page and it will detect the current account record Id and will display the complete hierarchy.</p><p>I am utilising formula field called "Ultimate Account id" to avoid multiple SOQL in apex to get list of all account in the hierarchy. This component can display all account which are up to 10 level deep in hierarchy.</p><p>Please refer below URL to get more idea about Ultimate Account Id formula field.</p><p><a href="https://www.sfdcstuff.com/2022/10/how-to-get-list-of-all-accounts-present.html" target="_blank">How to get list of all accounts present in account hierarchy in Salesforce</a><br /></p><p>In this LWC component, I am just passing the account Id to apex method and apex method returns all the account list which are present in hierarchy. In order to display account in tree grid, I am creating data in js which will be accepted by tree grid. So in this approach, manipulation on apex side is very simple.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBkjwcWy-Mb0gtPD-YpD2OLP1S4ibFEuLvfiL5yCm2VzpbaQrEefxMNW9xkBeAYxfeP6G1WaSifYeeIH_kgC97pLthOSwa8AbKHPibXYZmrhXwTsS89uFpUK1BB97Fsw4VP_3snmDISrD_NC99T7ToLsedlMvnIBHSy2UO_OX1qEcCKc0v_Uy72cl_/s1419/Account%20Hierarchy%20LWC.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="433" data-original-width="1419" height="98" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBkjwcWy-Mb0gtPD-YpD2OLP1S4ibFEuLvfiL5yCm2VzpbaQrEefxMNW9xkBeAYxfeP6G1WaSifYeeIH_kgC97pLthOSwa8AbKHPibXYZmrhXwTsS89uFpUK1BB97Fsw4VP_3snmDISrD_NC99T7ToLsedlMvnIBHSy2UO_OX1qEcCKc0v_Uy72cl_/w493-h98/Account%20Hierarchy%20LWC.PNG" width="493" /></a></div><br /><p>Note: Create Ultimate Account Id formula field on account first in order to implement below code.</p><p>Complete Code:</p><p><script src="https://gist.github.com/Sunil02kumar/1d7d8d10304f8635db9c9cebaecade69.js"></script></p><p>Hope this will help!!!</p><p><br /></p><p><br /></p><p><br /></p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com30tag:blogger.com,1999:blog-238133977370050645.post-81148848952878109442022-10-12T12:20:00.002+05:302022-10-12T14:46:53.529+05:30How to get list of all accounts present in account hierarchy in Salesforce<p> As a developer, we always get requirement to display records in their hierarchy (Account Hierarchy, Case Hierarchy etc). Using SOQL queries, its really tough to get all accounts in hierarchy as we have to fire multiple SOQL queries to get ultimate parent record id if we are on a record which is 3 or 4 level down in hierarchy. </p><p>Instead of achieving everything using SOQL, we can create formula field "Ultimate Account Id" in account object which will store ultimate account record id on all account records present in account hierarchy. As formula field allows you to refer upto 10 parent, we can easily get list of all account in account hierarchy upto 10 levels.</p><p><br /></p><p>Below is formula for Ultimate Account Id.</p><p><br /></p><p><script src="https://gist.github.com/Sunil02kumar/f017c233074fd7d3d1a20d1129e753fc.js"></script></p>Now if you know account record id, just get Ultimate Account Id field value and then query all accounts which have this ultimate account Id.<div><br /></div><div>Below is static method which can be used to get list of all account present in account hierarchy.</div><div><br /></div><div><div><span style="font-size: x-small;">public static list<Account> findAllHierarchyAccounts(string recordId){</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>list<Account> allAccountList=new List<Account>();</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>string ultimateAccountId;</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>for(Account acc:[select Ultimate_Account_Id__c from Account where Id=:recordId]){</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>ultimateAccountId=acc.Ultimate_Account_Id__c;</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>if(string.isNotBlank(ultimateAccountId)){</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>for(Account acc:[select id,Name,ParentId</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>from Account where Ultimate_Account_Id__c=:ultimateAccountId]){</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>allAccountList.add(acc);</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>}</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>system.debug('***allAccountList size:'+allAccountList);</span></div><div><span style="font-size: x-small;"><span style="white-space: pre;"> </span>return allAccountList;</span></div><div><span style="font-size: x-small;">}</span></div><div><span style="font-size: x-small;"><br /></span></div><div>Hope this will help!!</div><p><br /></p></div>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com6tag:blogger.com,1999:blog-238133977370050645.post-3593526770088975232022-04-20T20:53:00.002+05:302022-04-20T20:53:30.607+05:30Considerations for using Platform Events<p>Platform really helps in setting up custom notifications within salesforce or for external system. While utilising the platform events in salesforce, you need to consider below things:</p><p style="text-align: left;"></p><ul><li><b>Record Owner considerations</b></li></ul><p></p><div>Whenever you create record from after insert using triggers, then ownerid of those records will be Automated Process by default. If you have set current user as record owner, then specify ownerid of created records as createdbyId of event.</div><div><div><br /></div><div>Account acc= new Account(name='test account through Demo platform event',OwnerId = event.createdById);</div></div><p style="text-align: left;"></p><ul><li><b>Platform Event Trigger do not provide Email Support</b></li></ul>As automated process user does not have email address, sending an email message from a platform event trigger using the Messaging.SingleEmailMessage class is not supported. As a workaround, send emails via email alert where the From Email Address is NOT "Current User's Email Address" but rather some other organization-wide email or default workflow user. <p></p><p style="text-align: left;">In Apex, use the SingleEmailMessage.setOrgWideEmailAddressId method to set the org-wide email. </p><p style="text-align: left;">Hope this will help!!</p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com168tag:blogger.com,1999:blog-238133977370050645.post-39279134406071559302021-05-27T14:01:00.002+05:302021-06-15T17:40:07.432+05:30Useful system application events for lightning developement<p>Below is list of application events which is very useful and can be used frequently in lightning development.</p><p><b><u>Note: </u></b>These events are supported in Lightning Experience, the Salesforce mobile app, and Aura-based Experience Builder sites.</p><p><br /></p><p></p><p></p><ul style="text-align: left;"><li><b><u>force:closeQuickAction</u></b></li></ul><p></p><div><div>To close a quick action panel, you can use force:closeQuickAction event</div><div>var navEvent = $A.get("e.force:closeQuickAction");</div><div>if(navEvent){</div><div><span style="white-space: pre;"> </span>navEvent.fire();</div><div>}</div></div><div><br /></div><ul style="text-align: left;"><li><b><u>force:navigateToList</u></b></li></ul><div>This event helps you to navigate to list view based on ListviewId specified.</div><div><br /></div><div><div>var navEvent = $A.get("e.force:navigateToList");</div><div>if(navEvent){</div><div><span style="white-space: pre;"> </span>navEvent.setParams({</div><div><span style="white-space: pre;"> </span>"listViewId": listviews.Id,</div><div><span style="white-space: pre;"> </span>"listViewName": null,</div><div><span style="white-space: pre;"> </span>"scope": "Account"</div><div><span style="white-space: pre;"> </span>});</div><div><span style="white-space: pre;"> </span>navEvent.fire();</div><div>}</div></div><div> </div><div>How to get list view id using SOQL</div><div>SELECT Id FROM ListView WHERE SobjectType = 'Account' and Name='All Accounts' Limit 1</div><div><br /></div><ul style="text-align: left;"><li><b><u>force:navigateToURL</u></b></li></ul><div>This event helps you to navigate to URL specified in parameter.</div><div><br /></div><div><div>var navEvent= $A.get("e.force:navigateToURL");</div><div>if(navEvent){</div><div><span style="white-space: pre;"> </span>navEvent.setParams({</div><div> "url": "/001/"</div><div> });</div><div><span style="white-space: pre;"> </span>navEvent.fire();</div><div>}</div></div><div><br /></div><ul style="text-align: left;"><li><b><u>force:refreshView</u></b></li></ul><div>To refresh or reload standard or custom component, use this event. This event ideally reload data without page refresh.</div><div><br /></div><div><div>var navEvent= $A.get("e.force:refreshView");</div><div>if(navEvent){</div><div><span style="white-space: pre;"> </span>navEvent.fire();</div><div>}</div></div><div><br /></div><div><b><u>Note:</u> </b>This event impact performance and should be avoided. Also avoid repeated firing of this event from same component</div><div><br /></div><ul style="text-align: left;"><li><u><b>force:</b></u><b><u>showToast</u></b></li></ul><div>This event can be used to display message below the header at the top of a view. You can specify the message and type (warning, success, info, other) and based on that color of message panel will changes. Default is other which shows panel similar to info.</div><div><br /></div><div><div>showToastMessage:function(title,msg,duration,key,type,mode){</div><div><span style="white-space: pre;"> </span>var toastEvent = $A.get("e.force:showToast");</div><div><span style="white-space: pre;"> </span>if(toastEvent){</div><div><span style="white-space: pre;"> </span>toastEvent.setParams({</div><div><span style="white-space: pre;"> </span>"title": title,</div><div><span style="white-space: pre;"> </span>"message": msg,</div><div><span style="white-space: pre;"> </span>"duration":duration,</div><div><span style="white-space: pre;"> </span>"type": type,</div><div><span style="white-space: pre;"> </span>"mode": mode</div><div><span style="white-space: pre;"> </span>});</div><div><span style="white-space: pre;"> </span>toastEvent.fire();</div><div><span style="white-space: pre;"> </span>}</div><div>}</div></div><div><br /></div><div>Default value for mode is "dismissible" which display close icon. In duration you can specify the time in millisecond. Toast will remain in screen for this duration.</div><div><br /></div><div><b><u><br /></u></b></div><ul style="text-align: left;"><li><u><b>force:force:navigateToSObject</b></u></li></ul><div>This event help you to navigate to record details page based on recordId specified:</div><div><br /></div><div><div>var navEvent= $A.get("e.force:navigateToSObject");</div><div>if(navEvent){</div><div><span style="white-space: pre;"> </span>navEvent.setParams({</div><div><span style="white-space: pre;"> </span>"recordId": "003B0000000ybYX"</div><div><span style="white-space: pre;"> </span>});</div><div><span style="white-space: pre;"> </span>navEvent.fire();</div><div>}</div></div><div><br /></div><div><br /></div><div>Hope this help!!</div><p>
</p><ol style="text-align: left;"><p></p></ol>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com65tag:blogger.com,1999:blog-238133977370050645.post-75883873755728383762021-03-20T20:50:00.000+05:302021-03-20T20:50:03.051+05:30System.TypeException: Cannot have more than 10 chunks in a single operation<p> While working on requirement where we have to perform DML on multiple object dynamically by using sobject, we got below error:</p><p><br /></p><p><i>"System.TypeException: Cannot have more than 10 chunks in a single operation. Please rearrange the data to reduce chunking."</i></p><p><i><br /></i></p><p>This kind of error appears if your list of sobject contains more than 10 types of object records or record of objects are not ordered based on object. For example if you are adding lead, account and contact record to sobject list by using below format:</p><p>Lead1,Account1,Contact1,Lead2,Account2,Contact2,Lead3,Account3,Contact3,Lead4,Account4,Contact4</p><p>This will be considered as 12 chunks on sobject and while performing DML, you will get this error.</p><p>If you want to avoid it, then rearrange the records in below format:</p><p>Lead1,Lead2,Lead3,Lead4,Account1,Account2,Account3,Account4,Contact1,Contact2,Contact3,Contact4</p><p>This sequence of records will be considered as 3 chunks and is allowed in single DML operation.</p><p>Execute below script and you will get this error:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><p><i>List<sObject> sbList=new List<sObject>();</i></p><p><i>for(integer i=0;i<10;i++){</i></p><p><i> sblist.add(new Lead(lastname='Test Leat'+i,</i><i>company='test company'+i</i><i>));</i></p><p><i> sblist.add(new Account(name='Test Account'+i));</i></p><p><i> sblist.add(new Contact (lastname='test name'+i,email='test@gmail.com'+i));</i></p><p><i>}</i></p><p><i>insert sblist;</i></p></blockquote><p><i><br /></i></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV0lJfYcosMWQU_kr3j7oh1pVImv-SsCeDcbkbt62cF2npz4n3Cvs5Zbnt1jxycULy1FNOy64o8zMt9iA4C9rS7qLzTcp9utj_UOcdFonS-iSXajjXcqYnzANlfU1UQvINLg6ecEPU6U0/s1226/image1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="303" data-original-width="1226" height="99" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiV0lJfYcosMWQU_kr3j7oh1pVImv-SsCeDcbkbt62cF2npz4n3Cvs5Zbnt1jxycULy1FNOy64o8zMt9iA4C9rS7qLzTcp9utj_UOcdFonS-iSXajjXcqYnzANlfU1UQvINLg6ecEPU6U0/w400-h99/image1.PNG" width="400" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b><u>Ways to resolve this kind of error:</u></b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><ul style="text-align: left;"><li><u>Rearrange the records in list so that all records belonging to one object are stored together in list.</u></li></ul></div><p></p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><i>List<sObject> sbList=new List<sObject>();</i></div><div class="separator" style="clear: both;"><div><div><i>for(integer i=0;i<10;i++){</i></div></div></div><div class="separator" style="clear: both;"><div><div><i> sblist.add(new Lead(lastname='Test Leat'+i,company='test company'+i));</i></div></div></div><div class="separator" style="clear: both;"><div><div><i>}</i></div></div></div><div class="separator" style="clear: both;"><div><div><i>for(integer i=0;i<10;i++){</i></div></div></div><div class="separator" style="clear: both;"><div><div><i> sblist.add(new Account(name='Test Account'+i));</i></div></div></div><div class="separator" style="clear: both;"><div><div><i>}</i></div></div></div><div class="separator" style="clear: both;"><div><div><i>for(integer i=0;i<10;i++){</i></div></div></div><div class="separator" style="clear: both;"><div><div><i> sblist.add(new Contact (lastname='test name'+i,email='test@gmail.com'+i));</i></div></div></div><div class="separator" style="clear: both;"><div><div><i>}</i></div></div></div><div class="separator" style="clear: both;"><div><div><i>insert sblist;</i></div></div></div></blockquote><div class="separator" style="clear: both;"><div><i><br /></i></div><ul style="text-align: left;"><li><u>Sort the sobject list before performing DML</u></li></ul><div><u><br /></u></div></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><i>List<sObject> sbList=new List<sObject>();</i></div><div class="separator" style="clear: both;"><div><i>for(integer i=0;i<10;i++){</i></div></div><div class="separator" style="clear: both;"><div><i> sblist.add(new Lead(lastname='Test Leat'+i));</i></div></div><div class="separator" style="clear: both;"><div><i> sblist.add(new Account(name='Test Account'+i));</i></div></div><div class="separator" style="clear: both;"><div><i> sblist.add(new Contact (lastname='test name'+i,email='test@gmail.com'+i));</i></div></div><div class="separator" style="clear: both;"><div><i>}</i></div></div><div class="separator" style="clear: both;"><div><i>sblist.sort();</i></div></div><div class="separator" style="clear: both;"><div><i>insert sblist;</i></div></div></blockquote><div class="separator" style="clear: both;"><div><br /></div><div>Hope this will help!!</div></div><p><br /><i><br /></i></p><p><br /></p>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com25tag:blogger.com,1999:blog-238133977370050645.post-58668496130472903492020-07-26T21:26:00.002+05:302020-07-26T21:29:25.459+05:30Compare CRUD (Object Level Access) Permission for a Profile from 2 different OrgThrough this blog, I am going to share a script through which you can compare object level permission for a profile in 2 different SFDC orgs. This script is very helpful when you want to compare CRUD level permission for a profile in 2 different sandbox or permission in sandbox and production.<div><br /></div><div>When you run below script, you will receive email with csv file with CRUD permission comparison.</div><div>You need to specify the target org domain url and sessionid or access_token of target org and need to run below script in source org in execute anonymous window in developer console.</div><div><br /></div><div>Below is script:</div><div><script src="https://gist.github.com/Sunil02kumar/81a6e61ca74ad3f725462666c5e74009.js"></script></div><div><br /></div><div>Below is snapshot of csv file:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM7gRv7R4wmbSB6BqfHXj8wFvQVBmkJRc_jS-0SKMmXkxP-Nc_lB056o4IoNh4w9fR5_-88_3KuDKmBk9tStn7DnuDeML-m38rrIykQcV2fedC7CBXFeYQpH5CJExNmPH2T-jt4JzVymw/s2176/OLS+comparison.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="703" data-original-width="2176" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM7gRv7R4wmbSB6BqfHXj8wFvQVBmkJRc_jS-0SKMmXkxP-Nc_lB056o4IoNh4w9fR5_-88_3KuDKmBk9tStn7DnuDeML-m38rrIykQcV2fedC7CBXFeYQpH5CJExNmPH2T-jt4JzVymw/w500-h161/OLS+comparison.PNG" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b>Note:</b></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">This is just a prototype and it may work for small organization. You need to consider heap size and apex CPU time limit exceeded errors. You can refractor this code for your use based on number of objects that you have in your org.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Hope this will help!!</div><div><br /></div><div><br /></div><div><br /></div>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com20tag:blogger.com,1999:blog-238133977370050645.post-54767669049251757232020-06-26T14:14:00.002+05:302020-06-28T13:47:17.417+05:30Creating Package.xml from Changeset and Retrieving zip file containing Metadata using WorkbenchWe can utilize workbench to retrieve the package.xml and complete metadata in zip file for a changeset.<div><br /></div><div>Navigate to "migration" and then click retrieve.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs3fktyILXvN73lSXm_SBNRtUB77cFotgNF_V4RbuazYAw1YUICfE0tnNTnYGcQVlE67Nglmqf4UOnY36B5gp9XiDkAK5skZrbA0qt4v_-8gRlU4AZoE-mDaKeITGv3qr8EQ8QfESxlow/s1517/workbench1.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="257" data-original-width="1517" height="85" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs3fktyILXvN73lSXm_SBNRtUB77cFotgNF_V4RbuazYAw1YUICfE0tnNTnYGcQVlE67Nglmqf4UOnY36B5gp9XiDkAK5skZrbA0qt4v_-8gRlU4AZoE-mDaKeITGv3qr8EQ8QfESxlow/w500-h85/workbench1.PNG" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Enter changeset name. If you want to download package.xml for different changeset, then enter names seperated by comma.</div><div class="separator" style="clear: both; text-align: right;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-duPK_i5ubMMWd7xsutas-YB20gfbbyvYAd1Yg8OpifJke-ASfkIpzWwrpt9r9RgvFf3rY4lvC1TGsOjr0GHHF1cbz_Ja9_XwiuTxxy8-uxE1ieV8v1TOVzo1Dpgx8ug2yMHdi5D8O30/s1586/workbench2.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="539" data-original-width="1586" height="170" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-duPK_i5ubMMWd7xsutas-YB20gfbbyvYAd1Yg8OpifJke-ASfkIpzWwrpt9r9RgvFf3rY4lvC1TGsOjr0GHHF1cbz_Ja9_XwiuTxxy8-uxE1ieV8v1TOVzo1Dpgx8ug2yMHdi5D8O30/w500-h170/workbench2.PNG" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Click on "next" button and then retrieve button.</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQoNHdN1n50Ju8iC5iMNqpG_42-BJSalAvJSg0tq6znGU7_Z8R6mhfxCCjxW2Y7QHDFEcotmwGliay78EUX2u4_HNsmyrCB7vjugBo3zM-r_cLsNleDhUmWDIA59jMf1_mA47EYHyZtZw/s1535/workbench4.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="710" data-original-width="1535" height="231" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQoNHdN1n50Ju8iC5iMNqpG_42-BJSalAvJSg0tq6znGU7_Z8R6mhfxCCjxW2Y7QHDFEcotmwGliay78EUX2u4_HNsmyrCB7vjugBo3zM-r_cLsNleDhUmWDIA59jMf1_mA47EYHyZtZw/w500-h231/workbench4.PNG" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;">Download zip file and after extracting the files, you will get complete metadata and package.xml.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoaqaJ77FjXx9BIyvNGBe0BUPVkzbBxbbzixnnIYO61pFugIlk5eHYYBSz7qFwAolMrkF0apVNVhN5IcTzcZIZvLkem4n7OQf581Kiv_DDjhTBd14AwTnrHymMigUNxm8MF6DYpnn4xDc/s1527/workbench3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="922" data-original-width="1527" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoaqaJ77FjXx9BIyvNGBe0BUPVkzbBxbbzixnnIYO61pFugIlk5eHYYBSz7qFwAolMrkF0apVNVhN5IcTzcZIZvLkem4n7OQf581Kiv_DDjhTBd14AwTnrHymMigUNxm8MF6DYpnn4xDc/w500-h301/workbench3.PNG" width="500" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><b>Benefit of generating package.xml</b></div><div class="separator" style="clear: both; text-align: left;"><b><br /></b></div><div class="separator" style="clear: both; text-align: left;">Before deploying changeset to target org, you can extract package.xml from changeset. Now you can utilize this package.xml to extract metadta from target org before deployment which will work as backup for target org metadata. </div><div class="separator" style="clear: both; text-align: left;">Suppose you have to rollback after actual deployment, then you can utilize backup taken using package.xml to redeploy the old metadata in production.</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">Hope this will help!!</div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div><br /></div>Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com50tag:blogger.com,1999:blog-238133977370050645.post-51179199077179369682020-04-27T18:19:00.000+05:302020-04-27T18:24:49.521+05:30Javascript Promise.all : Way to perform action when Multiple Parallel enqueued Actions are Completed in Lightning Components<div dir="ltr" style="text-align: left;" trbidi="on">
As we all know that all actions from Lightning components are sent to server in asynchronous manner and we can not predict the sequence about response from server.<br />
<br />
If we have requirement to wait for all operations to complete and then perform some action on lightning components like hiding the spinner or displaying all data at once.<br />
<br />
We can either queue the first server call and when we get response then we perform second server call. For this you can use Javascript Promise pattern to sequence the server call. Please refer below URL for complete understanding of sequencing of server call using javascript promise.<br />
<br />
<a href="https://www.sfdcstuff.com/2020/04/javascript-promises-vs-callback.html">JavaScript Promises vs Callback Functions in Lightning Components</a><br />
<br />
Now if we need to fire server calls in parallel and want to wait for all response, then you can utilize promise.all methods to achieve this. This will execute many promises in parallel and wait until all of them are ready. Below is syntax to use promise.all:<br />
<pre class="language-markup"><code>
//create array of promise and pass it to promise.all
var promiseArray =[promise1, promise2];
var combinedPromise = Promise.all(promiseArray);
//this return single promise. Now handle it with then and catch
combinedPromise
.then($A.getCallback(function(results){
//handle success
var promise1Results = results[0]; //Results from Promise 1
var promise2Results = results[1]; //Results from Promise 2
}))
.catch($A.getCallback(function () {
//Handle errors on any promise here
console.log('Some error has occured');
}));
</code></pre>
<br />
Note:<br />
<ul style="text-align: left;">
<li>Promise.all takes an array of promises and returns a new promise.</li>
<li>The new promise resolves when all listed promises are settled, and the array of their results becomes its result.</li>
<li>Order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it’s still first in the array of results.</li>
<li>If any of the promises is rejected, the promise returned by Promise.all immediately rejects with that error.</li>
<li>For example, if there are multiple fetch calls and one fails, the others will still continue to execute, but Promise.all won’t watch them anymore. They will probably settle, but their results will be ignored. Promise.all does nothing to cancel them, as there’s no concept of “cancellation” in promises.</li>
<li>This will help to improve the performance of lightning components as server operations are not performed in sequential order. Due to parallel call to server, lightning components will perform better.</li>
</ul>
I have created a sample lightning component which fetch Account and Task records from server and displays it in UI only when both operations are completed and response is returned to lightning components. below is gif image displaying the lightning component functionality:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKjiOHVCeU8vsmaiS8TsKHv6ouIdlfXdrcQwNpUi2o1ZhbWxAS_fbI0Vc8MATQwixVpzF4RT7dvB9f6GzliTD8vqTQ8R-tUu5laP9GDIg-C44ictVYqAMWkTl5V6mVN-NC0zjHD3HkDrA/s1600/promiseall.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="707" data-original-width="756" height="373" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKjiOHVCeU8vsmaiS8TsKHv6ouIdlfXdrcQwNpUi2o1ZhbWxAS_fbI0Vc8MATQwixVpzF4RT7dvB9f6GzliTD8vqTQ8R-tUu5laP9GDIg-C44ictVYqAMWkTl5V6mVN-NC0zjHD3HkDrA/s400/promiseall.gif" width="400" /></a></div>
<br />
<br />
Below is complete snippet for your reference:<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/53aed3710d13c01c7af0fb616ff2f6b1.js"></script>
Hope this will help!!</div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com15tag:blogger.com,1999:blog-238133977370050645.post-7072312649010824252020-04-17T08:42:00.002+05:302020-04-17T10:58:59.800+05:30Get the Content (Blob) of File from Box and Store/Manipulate it in Salesforce<div dir="ltr" style="text-align: left;" trbidi="on">
Through this blog, I am going to share sample apex script through which you can get content of file from box as blob and then store or manipulate it within salesforce.<br />
<br />
I have already written a blog to explain how to get box access token (needed for handshake with Box) and to display file content in salesforce in VF page without storing it in salesforce. You can cosider it as Mashup inSalesforce. Please refer below URL to that:<br />
<br />
<a href="https://www.sfdcstuff.com/2015/06/box-and-salesforce-integration.html" target="_blank">Box and Salesforce Integration</a><br />
<b><br /></b>
In order to get box file content, we need to have box file Id and box access token.<br />
<br />
Box does not provide direct API to get file content. First you need to do callout to get download URL and then you perform another API callout to get file content. Also you perform another API call to get file details like filename in order to store it in salesforce.<br />
<br />
I am going to store box file in salesforce library for demo purpose. You can store it as attachments or read the content on the fly to perform some logic instead of saving it.<br />
<br />
Add below URLs in remote site settings before performing the callouts:<br />
<ul style="text-align: left;">
<li>https://api.box.com</li>
<li>https://dl.boxcloud.com </li>
</ul>
<br />
Below is required code and it is self explainatory as comments are mentioned for each methods:<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/e00ddc3d3198fe1500028fd6a775d62f.js"></script>
Now run below script in developer console:<br />
<br />
string boxFileId='6542xxx28604';<br />
string access_token='0xxxxxxxxxxxxxxxxxxxxxxxxxxxredx0P';<br />
string sfdcLibraryName='Box_File_Library';<br />
string boxFilename= SK_BoxAPIUtilityClass.findFileNameFromBox(boxFileId,access_token);<br />
system.debug('****boxFilename:'+boxFilename);<br />
SK_BoxAPIUtilityClass.readFileContentFromBox(boxFileId,boxFilename,sfdcLibraryName,access_token);<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmmW1anV266FwkU2zgFeuwfEfPPQOUb3dP1d9efRWJUDl3mqCFiqnu-R20YzaKpa9InCFMgXP2WlrKPhzllsOTegxGvpfeHrd6Qo0NHSeYQGmL3KgMJdA6bGcFhxLKt15VPOSoa8N1zbk/s1600/box123.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="385" data-original-width="930" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmmW1anV266FwkU2zgFeuwfEfPPQOUb3dP1d9efRWJUDl3mqCFiqnu-R20YzaKpa9InCFMgXP2WlrKPhzllsOTegxGvpfeHrd6Qo0NHSeYQGmL3KgMJdA6bGcFhxLKt15VPOSoa8N1zbk/s400/box123.JPG" width="400" /></a></div>
<br />
<b><br /></b>
<b>Use Case</b><br />
<b><br /></b>
During sandbox refresh, all custom settings data gets refreshed from production values. So before refresh, you have to take back up each custom settings data and after refresh, you need to update the custom setting records. In order to automate this, you can write script through which you can push all custom setting data to box folder. Code to upload the files from Salesforce to box is already shared in blog <a href="https://www.sfdcstuff.com/2015/06/box-and-salesforce-integration.html" target="_blank">Box and Salesforce Integration</a>.<br />
<br />
Now we need to get the content of all csv files stored in box and update the custom setting in salesforce. Once you get the content of file, you can parse csv file and update custom settings.<br />
<br />
Hope this helps!!!<br />
<br />
<br /></div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com119tag:blogger.com,1999:blog-238133977370050645.post-49299781690935715722020-04-11T02:50:00.002+05:302020-04-11T02:50:44.221+05:30JavaScript Promises vs Callback Functions in Lightning Components<div dir="ltr" style="text-align: left;" trbidi="on">
As we all know that all server calls from lightning components are asynchronous in nature. If we call 2 different apex methods from lightning components, then there is no surety that which will return response first. In order to provide sequencing between these 2 calls, we have to write second method call in callback function of first apex call as mentioned below:<br />
<br />
<pre class="language-markup"><code>findDataUsingNormalCall : function(component, event, helper) {
var actionName1= component.get("c.findMyAccounts");
var params1={"numberOfRecords":2};
actionName1.setParams(params1);
actionName1.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
var apexResponse1=response.getReturnValue();
component.set("v.ltngAccList",apexResponse1);
//Now perform second Call
var actionName2= component.get("c.findMyPendingTasks");
var params2={"numberOfRecords":2};
actionName2.setParams(params2);
actionName2.setCallback(this, function(response) {
state = response.getState();
if (state === "SUCCESS") {
var apexResponse2=response.getReturnValue();
component.set("v.ltngTaskList",apexResponse2);
}else if(state === "ERROR"){
var errors2 = response.getError();
console.error(errors2);
}
});
$A.enqueueAction(actionName2);
}else if(state === "ERROR"){
var errors1 = response.getError();
console.error(errors1);
}
});
$A.enqueueAction(actionName1);
</code></pre>
<br />
Now if you have to perform multiple server side apex calls from lightning components in sequential order, code becomes very difficult to understand and read and difficult to maintain this kind of code.<br />
<br />
<b><u>Javascript Promises</u></b><br />
<br />
Promise pattern is very common in javascript to handle asynchronous operations. Prior to promises events and callback functions were used but they had limited functionalities and created unmanageable code.<br />
<br />
Promise can have 3 states:
<br />
<div>
<ul style="text-align: left;">
<li>Pending</li>
<li>Fulfilled</li>
<li>Rejected</li>
</ul>
</div>
Use below syntax to create promise:<br />
<br />
<div>
<pre class="language-markup"><code>var promise1 = new Promise($A.getCallback(function(resolve, reject){
//perform logic like server call</code>
if (/* success */) {
resolve("result");
}else {
reject("error");
}
}));
</pre>
</div>
<ul style="text-align: left;">
<li>Constructor takes only one argument as a function. </li>
<li>Callback function takes two arguments, resolve and reject</li>
<li>Perform operations inside the callback function and if everything went well then call resolve.</li>
<li>If desired operations do not go well then call reject.</li>
</ul>
<div>
In order to consume promise, use .then or .catch methods as shown below:</div>
<div>
<br /></div>
<div>
<pre class="language-markup"><code>promise1 .
.then($A.getCallback(function(result){
//handle success
}),
$A.getCallback(function(error){
//handle error
})
)
.catch($A.getCallback(function () {
console.log('Some error has occured');
}));
</code></pre>
</div>
<div>
<br />
Remember:<br />
<ol style="text-align: left;">
<li>then() method automatically invoked when promise is either resolved (fulfilled) or reject.
</li>
<li>then() method takes 2 functions as parameters:</li>
<ul>
<li>If promise is resolved and a result is received, First function is executed.</li>
<li>If promise is rejected and an error is received, Second function is executed(optional).</li>
</ul>
<li>catch() method is invoked when a promise is either rejected or some error has occurred in execution. catch take 1 function as parameter. If you are using the second parameters for then function then use catch for error handling.</li>
</ol>
<div>
<u><b>Calling multiple asynchronous functions and Chaining them using Promises</b></u></div>
<div>
<u><b><br /></b></u></div>
<div>
You can use below pattern in order to perform different asynchronous operation in synchronous manner.</div>
<div>
<pre class="language-markup"><code><pre class="language-markup"><code>
new Promise($A.getCallback(function(resolve, reject){}))
.then(
// resolve handler
$A.getCallback(function(result) {
//when first call is successfull, then create new
//instance of promise to make another call
return new Promise($A.getCallback(function(resolve,reject){}));
}),
// reject handler
$A.getCallback(function(error) {
console.log("Promise was rejected: ", error);
//you can create another promise for error handling
})
)
.then(
// resolve handler
$A.getCallback(function() {
//perform logic when second call is successfull
})
);
</code></pre>
</code></pre>
</div>
<div>
I have created a sample lightning component which explain the functionality of callback function and promise pattern. Below are details about this component functionality:<br />
<ul style="text-align: left;">
<li>Component contains 2 button which invoke 2 different apex methods by using callback pattern and promise pattern.</li>
<li>When user clicks on "Fetch 2 records using callback pattern" button, system fires 2 server calls to get account and task records in asynchronous manner. So records will get displayed on UI based on response from server. There will be no sequencing of these 2 method invocation.</li>
<li>When user clicks on "Fetch 3 records using promise pattern", system first fire an asynchronous call to get account records and once account data is recieved, then it will fire another asynchronous call to get task records. This functionality uses promise pattern to fire 2 asynchronous call in synchronous manner. </li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKIdp4E3YTu4yyOH6d76XtrUA6sNfigw8YfE1T8LnNocfu9Qd6XLXFbo9iMyzYvsoZsRhGCP5YQxuKQI8Pj0eQchhGzWmHBzMaVs1-SzuwoOSzJxz9mfE4tB_359klLAft_JYfiIXuX4Q/s1600/promise.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="414" data-original-width="500" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKIdp4E3YTu4yyOH6d76XtrUA6sNfigw8YfE1T8LnNocfu9Qd6XLXFbo9iMyzYvsoZsRhGCP5YQxuKQI8Pj0eQchhGzWmHBzMaVs1-SzuwoOSzJxz9mfE4tB_359klLAft_JYfiIXuX4Q/s400/promise.gif" width="400" /></a></div>
<br />
<br />
Below is code snippet:<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/769616c6bc9f8447f102a347bcdef4f4.js"></script></div>
<div>
Best Practices:</div>
<div>
<ul style="text-align: left;">
<li>Always use catch or reject handler.</li>
<li>Always use $A.getCallback() when using promise pattern in lightning components. Even if you do not use this, then sometimes it will work but it will be very difficult to debug if something went wrong. Sometimes if you don't use it, then results may get delayed on UI and can cause performance issues. </li>
</ul>
<div>
Hope this will help!!</div>
</div>
</div>
</div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com29tag:blogger.com,1999:blog-238133977370050645.post-74959361945698212562020-01-30T13:55:00.000+05:302020-01-30T13:55:06.442+05:30Fetch All Workflow Email Alert Details Related to Object Using Tooling API<div dir="ltr" style="text-align: left;" trbidi="on">
Through this blog, I will sharing script which can help to get complete information about all the email alerts configured in Salesforce using workflow rules for any sObject.<br />
<br />
Imagine a scenario in which you need to extract all email alert configured or created for different workflow rules for specific object so that it can be reviewed or analyzed. If you do this activity manually then you have to open each workflow email alert and note down details like recipient, ccEmails, senderAddress, email template etc. This will be very hectic if you have lots of email configured.<br />
<br />
In order to solve this scenario, I am using Tooling API through which we can get complete details about workflow email alert. Through apex script, we can generate these details and send email (with csv file as attachment) to user with all details.<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/efc445404810df8094f76962aea8c805.js"></script>
First of all, inorder to parser JSON response, we need to create apex class (SK_EmailAlertJSONParser) which will act as parser for JSON. After this we can run the script in developer console and user will get email with all information regarding email alert.<br />
<br />
<br />
Below is snapshot of csv file that we will receive after running above script in developer console.<br />
I have specified objectId as "Contact". For custom object, specify 15 digit or 18 digit id.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjOh2gzXQSJWdlct5Jrjul-hwKyXVQ-JQKnHQL8LYde4OCt_I3DxvKn28exPLJkR8bZGUQf57Pw4mCxZSnXBW4pC9i2IUVVRiYoUU2vLloE5E0HnQLwGJ1GO2ArERLJrNvOujjmJrUiOg/s1600/Email+alert+csv+1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="285" data-original-width="1443" height="78" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjOh2gzXQSJWdlct5Jrjul-hwKyXVQ-JQKnHQL8LYde4OCt_I3DxvKn28exPLJkR8bZGUQf57Pw4mCxZSnXBW4pC9i2IUVVRiYoUU2vLloE5E0HnQLwGJ1GO2ArERLJrNvOujjmJrUiOg/s400/Email+alert+csv+1.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This script can be used to fetch information from other salesforce org also. Suppose you don't want to deploy this script in production, then save SK_EmailAlertJSOnParser class in sandbox and in developer console (using execute anonymous window) just specify the domainUrl for production and sessiond id production for admin user.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Don't forget to add domainUrl in remote site settings before running this script in execute anonymous window in developer console.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Hope this will help!!1</div>
<br /></div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com33tag:blogger.com,1999:blog-238133977370050645.post-37196452818094447092020-01-09T11:38:00.000+05:302020-01-09T11:38:16.952+05:30How to Delete all Files from Library using Apex<div dir="ltr" style="text-align: left;" trbidi="on">
If you have to delete any library, then first you have to delete all the files present in that library. For this purpose you can run below mentioned simple apex script to delete all files from library.<br />
<br />
<i>string LibraryName='Demo Library';</i><br />
<i>ContentWorkspace ws = [SELECT Id, RootContentFolderId FROM ContentWorkspace WHERE Name = :LibraryName LIMIT 1];</i><br />
<i>List<ContentDocument> contentDocumentIds = new List<ContentDocument>();</i><br />
<i>for(ContentDocumentLink con:[select id,LinkedEntityId,ContentDocumentId from ContentDocumentLink where LinkedEntityId=:ws.Id]){</i><br />
<i> contentDocumentIds.add(new ContentDocument(id=con.ContentDocumentId));</i><br />
<i>}</i><br />
<i>system.debug('********contentDocumentIds:'+contentDocumentIds);</i><br />
<i>system.debug('********contentDocumentIds.size:'+contentDocumentIds.size());</i><br />
<i>database.delete(contentDocumentIds,false);</i><br />
<i><br /></i>
<br />
Hope this will help!!</div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com5tag:blogger.com,1999:blog-238133977370050645.post-24404503107724787872020-01-08T22:36:00.000+05:302020-01-08T22:36:21.222+05:30Download Multiple Files from Libraries<div dir="ltr" style="text-align: left;" trbidi="on">
Consider a scenario in which we are suppose to download all files from libraries. Below are different approach which can be utilized:<br />
<br />
<u><b>Approach 1: Salesforce UI Download Button</b></u><br />
<br />
If the file size is around 60 or less in library then you can use Salesforce UI to download all files at one time.<br />
<br />
Open any library, click on show all button, then click on display options and select "Show 60 results per page". By doing this, you will be able to see 60 files at once in library. Now you can click on select all checkbox and click download button. This will help you to download files at once.<br />
If you have more than 60 files, then click on next page and then again download all files. This process will become hectic if you have more than 1000 files in library.<br />
<br />
<b><u>Approch 2:URL hack</u></b><br />
<br />
I performed some search on google and found out that there is another way to download all files as zip by specifying the contentversion Ids of file in URL. I can call it as URL hack and everyone mentioned that it is not recommended way. Below is URL format that you need to use:<br />
<br />
<i>https://xxxxxx.salesforce.com/sfc/servlet.shepherd/version/download/068xxxxxxxxxxxxxxx/068yyyyyyyyyyyyyyy/068wwwwwwwwwwwwwww/068zzzzzzzzzzzzz?</i><br />
<i><br /></i>
Just paste this URL and files will be downloaded as zip file.<br />
<br />
If you have more than 1000 files in library, then you have to build different URL by specifying 10 or 15 record id in one URL. I was able to download zip file with size around 400Mb using one URL.<br />
<br />
<b><u>Approach 3: Using Apex Script & Tab Save Chrome Extension</u></b><br />
<b><u><br /></u></b>
One of my friend told me about <a href="https://chrome.google.com/webstore/detail/tab-save/lkngoeaeclaebmpkgapchgjdbaekacki?hl=en" target="_blank">Tab Save </a> chrome extension. You just need to paste all files download url and click on download.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicCnM850oIPrWsVXu4ljmhBUowJMVvJX-UJgaczQxG6ygW0uLrkeT5yoI99RBFA2hngN8yFcOVx2rNkVmSIglgglNi-f37VMNs4jhCrGsbz6lkf8-2hdis8J4clGE3Gc9XRwrcgFc9PtA/s1600/Tab+Save.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="1600" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicCnM850oIPrWsVXu4ljmhBUowJMVvJX-UJgaczQxG6ygW0uLrkeT5yoI99RBFA2hngN8yFcOVx2rNkVmSIglgglNi-f37VMNs4jhCrGsbz6lkf8-2hdis8J4clGE3Gc9XRwrcgFc9PtA/s400/Tab+Save.png" width="400" /></a></div>
<br />
<br />
This will download all files in your downloads folder or folder that you have specified in chrome download settings.<br />
<br />
Now we wrote simple apex script which will send email with all URLs(file download URL) in csv file. Suppose you want to get download URLs for all files present in library "Demo Download Library", then refer below script:<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/396b9ec81b59a23aee29e5ca41a28202.js"></script>
Run above script in developer console by specifying your library name. You will receive email with all file download URLs. Now you just copy and paste these URLs in Tab Save edit window and click on download.<br />
<br />
I have used Tab Save extension to download around 1500 files and it was working fine.<br />
<br />
Now you have all 3 approaches and you can decide what to chose based on your requirements.<br />
<br />
Hope this will help!!<br />
<br />
<br />
<br /></div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com8tag:blogger.com,1999:blog-238133977370050645.post-54628490559120819602019-11-19T15:55:00.000+05:302019-11-19T15:55:46.719+05:30How to Convert Salesforce Classic Notes into Lightning Notes<div dir="ltr" style="text-align: left;" trbidi="on">
As now everyone is migrating to Lightning, Salesforce supports lightning Notes(ContentNote) instead of Classic Notes. So while migrating to lightning, we have to convert all classic Notes to lightning Notes. Salesforce provide an appexchange app called magic mover for this purpose.<br />
<br />
If you don't want to install this app and would like to perform this conversion, then you can do it with very simple apex script.<br />
<br />
If you want to understand How to Convert Salesforce Attachments into Salesforce Files then refer below URL:<br />
<br />
<a href="https://www.sfdcstuff.com/2019/11/how-to-convert-salesforce-attachments.html" target="_blank">Convert Salesforce Attachments into Salesforce Files</a><br />
<br />
<br />
I have created a batch class which will convert all Notes related to object (based on query that you pass) to ContentNote and you will receive an email with all details once batch job is completed.<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/5b2a95a27354e76e07a7e47878ee2440.js"></script>
Suppose you want to convert all the notes related to Account to Lightning Notes, then use below script in execute anonymous in developer console.<br />
<br />
<i>string qstring='Select id from Account';</i><br />
<i>SK_ConvertNotesForLightningBatch newjob= new SK_ConvertNotesForLightningBatch(qstring);</i><br />
<i>database.executeBatch(newjob);</i><br />
<i><br /></i>
Below is snapshot of csv file which you receive after this batch job completed.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF45G907GaZ63h855bBWo5T1mhO-RIFAjxdsHADfXzGBlCZ5UU4lj2QRXgPeevpZmCQ7-CbUCdzpF6OylvIrWt01g3g4Pqok_0FJOU1qS2aGl-O7G-fun-b66_QV3mUZUIrvTkLQcagns/s1600/notes+convert+1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="251" data-original-width="763" height="131" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF45G907GaZ63h855bBWo5T1mhO-RIFAjxdsHADfXzGBlCZ5UU4lj2QRXgPeevpZmCQ7-CbUCdzpF6OylvIrWt01g3g4Pqok_0FJOU1qS2aGl-O7G-fun-b66_QV3mUZUIrvTkLQcagns/s400/notes+convert+1.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Hope this will help!!</div>
<br /></div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com20tag:blogger.com,1999:blog-238133977370050645.post-28370833236407905712019-11-14T17:37:00.000+05:302019-11-14T17:37:03.183+05:30Pre-populate Field Values on Standard Pages in Lightning<div dir="ltr" style="text-align: left;" trbidi="on">
In Salesforce classic, we used to specify the field values in URL parameters (URL hacks) to pre-populate the field values in standard page layouts.<br />
<br />
In lightning, URL hack don't work. So if we have to open standard page in lightning with pre-populated field values, then we can use "e.force:createRecord" event to open new record page with default field values.<br />
<br />
In this blog, I will be creating a lightning component which will be added to account page layout. This component will display button "Create Quick Contact" to create new contact. When user will click on this button, standard new contact page will open with default field values.<br />
<br />
Below is complete code:<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/ec5aed3ff3ec4a46f4e833d59c6f17ed.js"></script>
Now you add this component on account page layout.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVIP8jW-cWT7MwpOFCu9maArNwy6UiteSEA3W32KTpJVemQby9wmvChMhnf6gWNoOds61gCc-mtLESQnGhyphenhyphenhDcnjFxd3x-93gcw3JJbqEmOARreIb9pcdFirno0lCtxQ5qSy33kXxx-TM/s1600/account1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="621" data-original-width="1209" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVIP8jW-cWT7MwpOFCu9maArNwy6UiteSEA3W32KTpJVemQby9wmvChMhnf6gWNoOds61gCc-mtLESQnGhyphenhyphenhDcnjFxd3x-93gcw3JJbqEmOARreIb9pcdFirno0lCtxQ5qSy33kXxx-TM/s400/account1.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Now when you click on Create Quick Contact, standard page will open for new contact creation with pre-filled field values specified in controller.js.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW12_WicxJx4UNtI0A_-HFdtPKdhCqPz6EjDuHJha7hNqI-hQuUowhFeZoL3-9ujkbolysj8KLC_vbxL0s0f-pJ_CJbpAVera5JXIuU19L-9FFZXncyt-AHAborcwe3FvvUAuU2EkOT58/s1600/account2.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="787" data-original-width="1277" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW12_WicxJx4UNtI0A_-HFdtPKdhCqPz6EjDuHJha7hNqI-hQuUowhFeZoL3-9ujkbolysj8KLC_vbxL0s0f-pJ_CJbpAVera5JXIuU19L-9FFZXncyt-AHAborcwe3FvvUAuU2EkOT58/s400/account2.JPG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Here you can see recordtypeId, phone, email and account are pre-populated.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Hope this will help!!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<br />
<br />
<br /></div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com14tag:blogger.com,1999:blog-238133977370050645.post-8084495922637115252019-11-07T13:49:00.001+05:302019-11-19T15:52:55.000+05:30How to Convert Salesforce Attachments into Salesforce Files<div dir="ltr" style="text-align: left;" trbidi="on">
As now everyone is migrating to Lightning, Salesforce supports files instead of attachment. So while migrating to lightning, we have to convert all attachments to files. Salesforce provide an appexchange app called magic mover for this purpose.<br />
<br />
If you don't want to install this app and would like to convert attachments to files, then you can do it with very simple apex script.<br />
<br />
I have created a batch class which will convert all attachments related to object (based on query that you pass) to files and you will receive an email with all details once batch job is completed.<br />
<br />
<script src="https://gist.github.com/Sunil02kumar/54abf6c3dcae839ece726f279c5b8a38.js"></script>
Suppose you have to convert all attachments of Contact to files, then use below script:<br />
<i>SK_ConvertAttachmentsToFilesBatch newjob= new SK_ConvertAttachmentsToFilesBatch('select id from Contact');</i><br />
<i>database.executeBatch(newjob, 1);</i><br />
<i><br /></i>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCfmS3sXpxWGIfbP-vxMByhG5rkj7vcqdbvPyNiQXFCCgG8KdseqD4n10hzxbuRsarhyXtCUTJ-xIn0vbn7fVylJtW9RCQhVy-3nWacfOGUojFapks-0vQrMh1YYDfMn1KYw96MZlPiuY/s1600/blog+image1.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="252" data-original-width="835" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCfmS3sXpxWGIfbP-vxMByhG5rkj7vcqdbvPyNiQXFCCgG8KdseqD4n10hzxbuRsarhyXtCUTJ-xIn0vbn7fVylJtW9RCQhVy-3nWacfOGUojFapks-0vQrMh1YYDfMn1KYw96MZlPiuY/s400/blog+image1.JPG" width="400" /></a></div>
<i><br /></i>
<i><br /></i>
I will suggest to run this batch job with minimum batch size (recommended size is 1). Suppose if you run this script with more batch size and one parent record have multiple attachments and attachment size is large, then you may face heap size error in apex script. So it is advisable to run this script with batch size as 1.<br />
<br />
Hope this will help!!</div>
Sunil Kumarhttp://www.blogger.com/profile/09681895934176598302noreply@blogger.com5