Saturday, 8 December 2018

Convert 15 character IDs to 18 character IDs in formula field

Hi ,

We have new method "CASESAFEID()"in formula field now to make 15 character Id to 18 character.

Classic
1. Go to Setup | Customize | object name | click Fields
a. For Custom objects: Setup Create Objects | object name
3. In the related list "Custom Fields & Relationships" click New.
4. Click the Formula radio button.
5. Click the Text radio button for 'Formula Return Type.'
6. Input the following Formula into the Formula Editor:
CASESAFEID(Id)

7. Set Field Visibility, add or remove from the page layout.
 8. Click Save.

Lightning
 
1. Go to Setup Object Manager | Object name | Fields & Relationships
2. Click New.
3. Click the Formula radio button.
4. Click the Text radio button for 'Formula Return Type.'
5. Input the following formula into the Formula Editor:
CASESAFEID(Id)

6. Set Field Visibility, add or remove from the page layout.
7. Click Save.


Reference:
https://help.salesforce.com/articleView?id=000005288&language=en_US&type=1

Sunday, 25 November 2018

Run Script After Sandbox Creation and Refresh

Hi ,
We have an interface SandboxPostCopy from salesforce.com to do data manipulation after sandbox is created or refresh.
It makes our  sandbox environment business ready, automate data manipulation or business logic tasks.
At sandbox creation, specify a single Apex class to perform the tasks. This class executes every time the sandbox is copied.
Lightning interface of sandbox post-copy script specification

Create an Apex class that implements SandboxPostCopy and specify the class here. For example, the following Apex class simply reports the three contexts available in SandboxPostCopy: your organization ID, sandbox ID, and sandbox name:
Example:
global class HelloWorld implements SandboxPostCopy {
  global void runApexClass(SandboxContext context) {
      System.debug('Hello Tester Pester ' + context.organizationId()
           + ' ' + context.sandboxId() + context.sandboxName()); 
    }
  }

you can write your business logic in the method "runApexClass"

Reference:
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_interface_System_SandboxPostCopy.htm?search_text=SandboxPostCopy#apex_interface_System_SandboxPostCopy_Example
https://docs.releasenotes.salesforce.com/en-us/spring16/release-notes/rn_deployment_sandbox_postcopy_script.htm





Monday, 19 November 2018

SFDX with Non Scratch Orgs

Hi ,

Gave demo on SFDX with Non Scratch orgs in our Salesforce Techbook Channel. You can learn how to use SFDX with Non Scratch orgs after this demo.





References:

https://trailhead.salesforce.com/en/content/learn/trails/sfdx_get_started
SFDX CLI:https://developer.salesforce.com/tools/sfdxcli
VS Code:https://code.visualstudio.com/download
Salesforce Extensions:
https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode






Monday, 12 November 2018

Software installations for SFDX setup

Hi ,

We need to setup the following software in the order mentioned



1)Install Java8 (jdk 8)  and set path
2)Install SFDXCLI "https://developer.salesforce.com/tools/sfdxcli" and set path
3)Install VS Code
4)Install "Salesforce Extension Pack" in VS code  (Under extensions section search for Salesforce Extensions for Visual Studio Code)



Reference:

https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm#sfdx_setup_install_cli

Sunday, 14 October 2018

Get Record Type Id from lightning component in standard new action override (getting any url parameter)

Hi ,

Here we have requirement to get record type id from lightning component when standard "New" action is overrided.


To get selected RecordTypeId from the component we have to implement the lightning interface "lightning:isUrlAddressable" which will be useful to access parameter "RecordTypeId" from the top level.


Eg:

Ligthtning Component:
----------------------------

<aura:component implements="lightning:isUrlAddressable" description="c:helloTarget component">
    <aura:attribute name="firstname" type="String" />
    <aura:handler name="init" value="{!this}" action="{!c.init}"/>
    Hello {!v.firstname}.
</aura:component>

JavascriptController:
-------------------------
({
    init: function(cmp, evt, helper) {
        var myPageRef = cmp.get("v.pageReference");
        var firstname = myPageRef.state.RecordTypeId;
        cmp.set("v.firstname", firstname);
    }
})



References:
---------------
https://developer.salesforce.com/docs/component-library/bundle/lightning:isUrlAddressable/documentation



lightning:workspaceAPI on Lightning Console Applications (Getting record id from record tab)

Hi ,

To access tabs or sub tabs information in Salesforce Classic console application we have Console Integration Toolkit.
In the same way to access tabs or sub tabs information in Lightning Conosle Application we have to use "workspaceAPI".
To access methods of "workspaceAPI" we have to create an instance of the lightning:workspaceAPI component and assign an aura:id attribute to it as shown below .

<lightning:workspaceAPI aura:id="workspace"/>

This component allows you to access methods for programmatically controlling workspace tabs and subtabs in a Lightning console app. In Lightning console apps, records open as workspace tabs and their related records open as subtabs.

Scenario:
When a record is opened in Lighning Console application  we should be able to find out the record ID from the record tab, for further process from application utility menu items.

Eg:


<aura:component                  implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,force:appHostable" 
                access="global"  controller="UpdateCaseController">
    <lightning:workspaceAPI aura:id="workspace" />

    <aura:attribute name="recordId" type="String"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
</aura:component>


JSController:

({
doInit : function(component, event, helper) {
        
        var workspaceAPI = component.find("workspace");
        workspaceAPI.getTabInfo().then(function(response) {
                       var action = component.get("c.updateCase");        
                       action.setParams({"caseRecordId":response.recordId});
                       action.setCallback(this,function(data){
                             var result = data.getReturnValue();
                              
                     });
                    $A.enqueueAction(action);
        });
})

Apex Controller:

public class UpdateCaseController{
  @Auraenabled
   public static void updateCase(String caseRecordId){
       Case caseObj = new Case(Id=caseRecordId,ownerId=UserInfo.getUserId());
        update caseObj;
   }
   

}


Reference:

https://developer.salesforce.com/docs/component-library/bundle/lightning:workspaceAPI/documentation

https://developer.salesforce.com/docs/atlas.en-us.api_console.meta/api_console/sforce_api_console_methods_lightning_tabs.htm





Saturday, 29 September 2018

Lightning Data Service Considerations (limitations)

Hi,

We have few limitations on Lightning Data Service. We have to consider these before we use the same for any implementation.

Lightning Data Service is powerful and simple to use. However, it’s not a complete replacement for writing your own data access code. Here are some considerations to keep in mind when using it.
Lightning Data Service is only available in Lightning Experience and the Salesforce app. Using Lightning Data Service in other containers, such as Lightning Components for Visualforce or Lightning Out, isn’t supported. This is true even if these containers are accessed inside Lightning Experience or the Salesforce mobile app, for example, a Visualforce page added to Lightning Experience.

Lightning Data Service supports primitive DML operations—create, read, update, and delete. It operates on one record at a time, which you retrieve or modify using the record ID. Lightning Data Service supports spanned fields with a maximum depth of five levels. Support for working with collections of records or for querying for a record by anything other than the record ID isn’t available. If you must support higher-level operations or multiple operations in one transaction, use standard @AuraEnabled Apex methods.

Lightning Data Service shared data storage provides notifications to all components that use a record whenever a component changes that record. It doesn’t notify components if that record is changed on the server, for example, if someone else modifies it. Records changed on the server aren’t updated locally until they’re reloaded. Lightning Data Service notifies listeners about data changes only if the changed fields are the same as in the listener’s fields or layout.





Reference:

https://trailhead.salesforce.com/modules/lightning_data_service/units/lightning_data_service_get_started

https://developer.salesforce.com/docs/atlas.en-us.214.0.lightning.meta/lightning/data_service_considerations.htm

Sunday, 26 August 2018

Salesforce Techbook (New Youtube Channel)

Hi ,

Have started new youtube channel "Salesforce Techbook" for providing useful examples.The following video published on "Salesforce Techbook" channel. Interested people can subscribe.

Please find the below URL (lightning component development):

https://www.youtube.com/watch?v=xMzPhu01ptc&lc=z22ihbcbwuqbzzwxf04t1aokgsnmccfanmrqqukxt4pabk0h00410

Channel URL:

https://www.youtube.com/channel/UCipDch4PvPqm0uY4SK7mi1A

Future Concepts:

https://www.youtube.com/watch?v=HA7-gkQH2bE

All the best

Interface Reference of Lightning


Implement these platform interfaces to allow a component to be used in different contexts, or to enable your component to receive extra context data. A component can implement multiple interfaces. Some interfaces are intended to be implemented together, while others are mutually exclusive. Some interfaces have an effect only in Lightning Experience and the Salesforce app.

Interfaces belong to different namespaces, including:

clients
Provides interfaces that are specific to Lightning for Outlook or Lightning for Gmail.
flexipage
Provides interfaces that are specific to Lightning Pages and the Lightning App Builder.
force
Provides interfaces that are specific to Lightning Experience and the Salesforce app.
forceCommunity
Provides interfaces that are specific to Communities.
lightning
Provides interfaces that are specific to Lightning Experience, the Salesforce app, and Communities.
ltng
Provides events that are handled by Lightning Out.
Some of these interfaces are summarized below. For a complete list, refer to the Component Library.

clients:availableForMailAppAppPage
To appear in the Lightning App Builder or a Lightning Page in Lightning for Outlook or Lightning for Gmail, a component must implement the clients:availableForMailAppAppPage interface. 
clients:hasEventContext
Enables a component to be assigned to an event’s date or location attributes in Lightning for Outlook and Lightning for Gmail. 
clients:hasItemContext
Enables a component to be assigned to an email’s or a calendar event’s item attributes in Lightning for Outlook and Lightning for Gmail.
flexipage:availableForAllPageTypes
A global interface that makes a component available in the Lightning App Builder, and for any type of Lightning page.
flexipage:availableForRecordHome
If your component is designed only for record pages, implement the flexipage:availableForRecordHome interface instead of flexipage:availableForAllPageTypes
forceCommunity:availableForAllPageTypes
To appear in Community Builder, a component must implement the forceCommunity:availableForAllPageTypes interface. 
force:appHostable
Allows a component to be used as a custom tab in Lightning Experience or the Salesforce app. 
force:lightningQuickAction
Allows a component to display in a panel with standard action controls, such as a Cancel button. These components can also display and implement their own controls, but should handle events from the standard controls. If you implement force:lightningQuickAction, you can’t implement force:lightningQuickActionWithoutHeader within the same component.
force:lightningQuickActionWithoutHeader
Allows a component to display in a panel without additional controls. The component should provide a complete user interface for the action. If you implement force:lightningQuickActionWithoutHeader, you can’t implement force:lightningQuickAction within the same component. 
ltng:allowGuestAccess
Add the ltng:allowGuestAccess interface to your Lightning Out dependency app to make it available to users without requiring them to authenticate with Salesforce. This interface lets you build your app with Lightning components, and deploy it anywhere and to anyone. 

References:
https://developer.salesforce.com/docs/component-library/overview/interfaces
https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/ref_interfaces.htm


Thursday, 26 July 2018

Get the Developer Name for Record Types without SOQL query

Hi,

Previously, the developer name was accessible only via SOQL on the RecordType SObject, and not via describe information. Now you can use the following methods to get the developer name.


  • Schema.DescribeSObjectResult.getRecordTypeInfosByDeveloperName()
  • Schema.RecordTypeInfo.getDeveloperName()


Sample Codes:

Getting Record Type Id based on Developer Name:

Schema.DescribeSObjectResult resSchema = Department__C.sObjectType.getDescribe();
//getting all Recordtype developer names of Department__c object
Map<String,Schema.RecordTypeInfo>  recordTypeInfo = resSchema.getRecordTypeInfosByDeveloperName(); 
//Getting IT Department Record Type Id by using developer name ''IT_Department"
Id recordTypeId= recordTypeInfo.get('IT_Department').getRecordTypeId();
System.debug('recordTypeId:'+recordTypeId);

Getting RecordType Developer Name based on Name(Label):


Schema.DescribeSObjectResult resSchema = Department__C.sObjectType.getDescribe();
//getting all Recordtype developer names Account
Map<String,Schema.RecordTypeInfo> recordTypeInfo = resSchema.getRecordTypeInfosByName(); 
//Getting Business Record Type Id by using developer name 
String developerName = recordTypeInfo.get('IT Department').getDeveloperName();

System.debug('developerName:'+developerName);


Reference:

https://trailhead.salesforce.com/modules/platform_dev_i_cert_maint_sum18/units/whats_new_platform_devs


Thursday, 21 June 2018

Refresh Interval of different types of Sandboxes

Hi,

We have different refresh intervals for different sandboxes as shown below.

Sandbox Type
Refresh Interval
Storage Limit
What’s Copied
Developer Sandbox
1 day
Data storage: 200 MB
File storage: 200 MB
Metadata only
Developer Pro Sandbox
1 day
Data storage: 1 GB
File storage: 1 GB
Metadata only
Partial Copy Sandbox
5 days
Data storage: 5 GB
File storage: 5 GB
Metadata and sample data
Full Sandbox
29 days
Same as your production org
Metadata and all data


Reference:

https://trailhead.salesforce.com/modules/app_deployment/units/app_deployment_sandbox?trailmix_creator_id=00550000006yDdKAAU&trailmix_id=architect-dev-lifecycle-and-deployment

Sandbox Types in Salesforce.com

Hi ,

We have different types of sandboxes as below.

Developer Sandbox
A Developer sandbox is intended for development and testing in an isolated environment. A Developer Sandbox includes a copy of your production org’s configuration (metadata).
Developer Pro Sandbox
A Developer Pro sandbox is intended for development and testing in an isolated environment and can host larger data sets than a Developer sandbox. A Developer Pro sandbox includes a copy of your production org’s configuration (metadata). Use a Developer Pro sandbox to handle more development and quality assurance tasks and for integration testing or user training.
Partial Copy Sandbox
A Partial Copy sandbox is intended to be used as a testing environment. This environment includes a copy of your production org’s configuration (metadata) and a sample of your production org’s data as defined by a sandbox template. Use a Partial Copy sandbox for quality assurance tasks such as user acceptance testing, integration testing, and training.
Full Sandbox
A Full sandbox is intended to be used as a testing environment. Only Full sandboxes support performance testing, load testing, and staging. Full sandboxes are a replica of your production org, including all data, such as object records and attachments, and metadata. The length of the refresh interval makes it difficult to use Full sandboxes for development.
We recommend that you apply a sandbox template so that your sandbox contains only the records that you need for testing or other tasks.



Sandbox Type
Professional Edition
Performance Edition
Unlimited Edition
Developer Sandbox
10 (change sets not available)
100
100
Developer Pro Sandbox
5
5
Partial Copy Sandbox
1
1
Full Sandbox
1
1



References:

https://trailhead.salesforce.com/modules/app_deployment/units/app_deployment_sandbox?trailmix_creator_id=00550000006yDdKAAU&trailmix_id=architect-dev-lifecycle-and-deployment

Monday, 16 April 2018

Getting Reference FieldsI(Lookup or Master detail) through dynamic apex

Hi ,

We  had a scenario

If  we get a parameter "id" in the  url  then we should  be  able to find out    object reference is present in  the object which we are  trying  to insert then we have to make it  child record for  the object  related  to id.

For eg :

On my vf page i am trying  to insert  a contact and  i got  a parameter id related to Account

through the below code  i can find out  the  field which is  reference  to  Account  and  then fill that with parameter id to get contact inserted  under account.
The following code useful getting  reference fields  under  an object not  whole  example.



Eg: Code for  getting  reference

Map<String,Schema.SObjectField>  sobjecFieldMap = schema.getGlobalDescribe().get('Contact').getDescribe().fields.getMap();
for(String fieldName:sobjecFieldMap.keyset()){ 
    if(sobjecFieldMap.get(fieldName).getDescribe().getType()== Schema.DisplayType.REFERENCE){
       System.debug(sobjecFieldMap.get(fieldName).getDescribe().getReferenceTo());
    }
   
}


Output:
---------
Contact
Account
User




Sunday, 8 April 2018

Custom Lookup Creation and Example in Lightning

Hi ,

Lets how to prepare custom lookup component


Here in this example i am using "svg" component for icons but you can use lightning:icon tag instead


1)Create LC_svg component:

<aura:component >
    <aura:attribute name="class" type="String" description="CSS classname for the SVG element" />
    <aura:attribute name="xlinkHref" type="String" description="SLDS icon path. Ex: /assets/icons/utility-sprite/svg/symbols.svg#account" />
    <aura:attribute name="aria-hidden" type="String" default="true" description="aria-hidden true or false. defaults to true" />
</aura:component>

Renderer:
({
render: function(component, helper) {
//grab attributes from the component markup
var classname = component.get("v.class");
var xlinkhref = component.get("v.xlinkHref");
var ariaHidden = component.get("v.aria-hidden");

//return an svg element w/ the attributes
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('class', classname);
svg.setAttribute('aria-hidden', ariaHidden);
svg.innerHTML = '<use xlink:href="'+xlinkhref+'"></use>';
return svg;
}
})


2)Create SelectedObject event and  Custom Lookup Result component for getting the list of accounts based  search keyword


SelectedObject.evt:

<aura:event type="COMPONENT" description="by this event we are passing the selected Record in the Obeerving Component">
    <aura:attribute name="RecordByEvent" type="sObject"/>
</aura:event>

CustomLookupResult.cmp

<aura:component >
    <aura:attribute name="Obj" type="sObject" />
  <!--Register the component level event-->
    <aura:registerEvent name="oSelectedObjectEvent" type="c:SelectedObject"/>
    
    <li role="presentation">
        <span class="slds-lookup__item-action slds-media slds-media--center" id="lookup-option-350" role="option">
         <div class="slds-media__body">
          <div class="slds-input-has-icon slds-input-has-icon--right">
            <c:LC_svg class="slds-input__icon" xlinkHref="{!$Resource.SLDS092 + '/assets/icons/standard-sprite/svg/symbols.svg#account'}" />                   
          
<div class="slds-lookup__result-text"><a onclick="{!c.selectRecord}">{!v.Obj.Name}</a></div>
          </div>
        </div>    
        </span>
    </li>
</aura:component>

CustomLookupResultController.js:
----------------------------------------------------
({
selectRecord : function(component, event, helper){      
    // get the selected Account from list  
      var getSelectRecord = component.get("v.Obj");
    // call the event   
      var compEvent = component.getEvent("oSelectedObjectEvent");
    // set the Selected Object to the event attribute.  
     compEvent.setParams({"RecordByEvent" : getSelectRecord });  
    // fire the event  
     compEvent.fire();
    },
})


3)Create PickListEvt.evt and CustomLookup.cmp component:

PickListEvt.evt:
---------------------
<aura:event type="Component" description="Event fire when some one selects a value in picklist" >
    <aura:attribute name="SelectedValue" type="string" description="The result of the Selection"/>
</aura:event>

CustomLookup.cmp
---------------------------
/*
 This is the Controller Class for the Custom Lookup component.
 */
public class LookUpController {
  @AuraEnabled
 public static List <sObject> fetchRecords(String searchKeyWord, String ObjName, string count) {
  String searchKey = searchKeyWord + '%';
  List < Sobject > lstOfObj =  Database.query('SELECT id, Name '+' FROM '+ObjName+' WHERE Name LIKE \''+searchKey+'\' limit ' + count);
 
  return lstOfObj ;
 }
}


<aura:component controller="LookUpController" >    
   <aura:registerEvent name="RecordSelected" type="c:PickListEvt" description="This will Fire when the records has reached in it"/>
   <aura:attribute name="selectedRecord" type="sObject" default="{}" description="Use,for store SELECTED sObject Record"/>
   <aura:attribute name="listOfSearchRecords" type="sObject[]" description="Use,for store the list of search records which returns from apex class"/>
   <aura:attribute name="SearchKeyWord" type="string"/>
   <aura:attribute name="FieldLabel" type="String"/>
   <aura:attribute name="ObjName" type="string" default="Account"/>
   <aura:attribute name="RecordCount" type="string" default="10"/>
   <aura:attribute name="Message" type="String" default="Search Result.."/>
    
   <!--declare events handlers-->  
   <aura:handler name="oSelectedObjectEvent" event="c:SelectedObject" action="{!c.handleComponentEvent}"/>
   <aura:handler event="aura:waiting" action="{!c.showSpinner}"/>
   <aura:handler event="aura:doneWaiting" action="{!c.hideSpinner}"/>
   <div class="slds-m-around">
      <div aura:id="searchRes" class="slds-form-element slds-lookup slds-is-close" data-select="single">
          <aura:if isTrue="{!!empty(v.FieldLabel)}">
         <label class="slds-form-element__label" for="lookup-348"> {!v.FieldLabel}</label>
          </aura:if>
         <!--This part is for display search bar for lookup-->  
         <div class="slds-form-element__control">
            <div class="slds-input-has-icon slds-input-has-icon--right">
               <c:LC_svg class="slds-input__icon slds-show" xlinkHref="{!$Resource.SLDS092 + '/assets/icons/utility-sprite/svg/symbols.svg#search'}" />
               <!-- This markup is for when an record is selected -->
               <div aura:id="lookup-pill" class="slds-pill-container slds-hide">
                  <span class="slds-pill">
                     <span class="slds-pill__label">
                       {!v.selectedRecord.Name} 
                     </span>
                     <span class="slds-button slds-button--icon slds-pill__remove deleteIcon" onclick="{!c.clear}">
                        <c:LC_svg class="slds-button__icon" xlinkHref="{!$Resource.SLDS092 + '/assets/icons/utility-sprite/svg/symbols.svg#close'}" />
                        <span class="slds-assistive-text">Remove</span>
                     </span>
                  </span>
               </div>
              <div aura:id="lookupField" class="slds-show">
               <ui:inputText updateOn="keyup" keyup="{!c.keyPressController}" aura:id="LookupGeneral"
                             class="slds-lookup__search-input slds-input " 
                             value="{!v.SearchKeyWord}" placeholder="search.." />
              </div>   
            </div>
         </div>
         <!--This part is for Display typehead lookup result List-->  
         <div class="slds-lookup__menu slds" id="lookup-348">
            <div class="slds-lookup__item--label slds-text-body--small">{!v.Message}</div>
            <center> <ui:spinner aura:id="spinner"/> </center>
            <ul class="slds-lookup__list" role="listbox">
               <aura:iteration items="{!v.listOfSearchRecords}" var="singleRec">
                  <c:CustomLookupResult Obj="{!singleRec}" />
               </aura:iteration>
            </ul>
         </div>
      </div>
   </div>
</aura:component>


CustomLookupController.js:

({
  
keyPressController : function(component, event, helper) {
      // get the search Input keyword   
var getInputkeyWord = component.get("v.SearchKeyWord");
        var getObjName = component.get("v.ObjName");
        var getRecordCount = component.get("v.RecordCount");
      // check if getInputKeyWord size id more then 0 then open the lookup result List and 
      // call the helper 
      // else close the lookup result List part.   
        if( getInputkeyWord.length > 0 ){
             var forOpen = component.find("searchRes");
               $A.util.addClass(forOpen, 'slds-is-open');
               $A.util.removeClass(forOpen, 'slds-is-close');
            helper.searchHelper(component,event,getInputkeyWord, getObjName, getRecordCount);
        }
        else{  
            component.set("v.listOfSearchRecords", null ); 
             var forclose = component.find("searchRes");
               $A.util.addClass(forclose, 'slds-is-close');
               $A.util.removeClass(forclose, 'slds-is-open');
          }
         
},
  
  // function for clear the Record Selaction 
    clear :function(component,event,heplper){
      
         var pillTarget = component.find("lookup-pill");
         var lookUpTarget = component.find("lookupField"); 
         $A.util.addClass(pillTarget, 'slds-hide');
         $A.util.removeClass(pillTarget, 'slds-show');
        
         $A.util.addClass(lookUpTarget, 'slds-show');
         $A.util.removeClass(lookUpTarget, 'slds-hide');
      
         component.set("v.SearchKeyWord",null);
         component.set("v.listOfSearchRecords", null );
         
    },
    
  // This function call when the end User Select any record from the result list.   
    handleComponentEvent : function(component, event, helper) {
    // get the selected Account record from the COMPONETN event  
       var selectedRecordGetFromEvent = event.getParam("RecordByEvent");
       var RecordSelected = component.getEvent("RecordSelected");     
         RecordSelected.setParams({
            SelectedValue: selectedRecordGetFromEvent.Id
        }).fire();
       component.set("v.selectedRecord" , selectedRecordGetFromEvent); 
       
        var forclose = component.find("lookup-pill");
           $A.util.addClass(forclose, 'slds-show');
           $A.util.removeClass(forclose, 'slds-hide');
        
        var forclose = component.find("searchRes");
           $A.util.addClass(forclose, 'slds-is-close');
           $A.util.removeClass(forclose, 'slds-is-open');
         
        var lookUpTarget = component.find("lookupField");
            $A.util.addClass(lookUpTarget, 'slds-hide');
            $A.util.removeClass(lookUpTarget, 'slds-show'); 
           
      
},
  // automatically call when the component is done waiting for a response to a server request.  
    hideSpinner : function (component, event, helper) {
        var spinner = component.find('spinner');
        var evt = spinner.get("e.toggle");
        evt.setParams({ isVisible : false });
        evt.fire();    
    },
 // automatically call when the component is waiting for a response to a server request.
    showSpinner : function (component, event, helper) {
        var spinner = component.find('spinner');
        var evt = spinner.get("e.toggle");
        evt.setParams({ isVisible : true });
        evt.fire();    
    },
    
})

CustomLookupHelper.js
-----------------------------------
({
searchHelper : function(component,event,getInputkeyWord, getObjName, getRecordCount) {
  // call the apex class method 
     var action = component.get("c.fetchRecords");
      // set param to method  
        action.setParams({
            'searchKeyWord': getInputkeyWord,
            'ObjName' : getObjName,
            'count' : getRecordCount
          });
      // set a callBack    
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var storeResponse = response.getReturnValue();
              // if storeResponse size is equal 0 ,display No Result Found... message on screen.
                if (storeResponse.length == 0) {
                    component.set("v.Message", 'No Result Found...');
                } else {
                    component.set("v.Message", 'Search Result...');
                }
                
                // set searchResult list with return value from server.
                component.set("v.listOfSearchRecords", storeResponse);
            }
 
        });
      // enqueue the Action  
        $A.enqueueAction(action);
    
},
})


Custom Lookup Example: (Usage):

CustomLookupExample.cmp:
---------------------------------------
<aura:component controller="ContactSavecls">
    <aura:attribute name="contactObj" type="Contact" default="{'sobjectType':'Contact',
                                                              'AccountId':'','FirstName':'',
                                                               'LastName':''}"/>
    <div>
    <div class="slds-form-element__control">
        <ui:inputText class="slds-input" label="Last Name" value="{!v.contactObj.LastName}"/>
        <c:CustomLookup ObjName="Account" FieldLabel="Related Account"
            RecordCount="5" 
            RecordSelected="{!c.handleRecordSelection}" />
       </div>    
        <ui:button press="{!c.contactSave}">Save Contact</ui:button>
    </div>
</aura:component>

CustomLookupExample.js:
-------------------------------------
({
handleRecordSelection : function(component, event, helper) {
        alert('hi'+event.getParam("SelectedValue"));
component.set("v.contactObj.AccountId", event.getParam("SelectedValue"));
},
    contactSave:function(component, event, helper){
        var action = component.get("c.saveContact");
        var contRec = component.get("v.contactObj");
        action.setParams({"contObj":contRec});
        action.setCallback(this,function(data){
            var result = data.getReturnValue();
            alert(result);
        });
        $A.enqueueAction(action);
        
    }
})



ApexController:
--------------------
public class ContactSavecls{
    @Auraenabled
    public static String saveContact(Contact contObj){
        insert contObj;
        return contObj.Id;
    }
}



output:
------------




References:
------------------
https://developer.salesforce.com/blogs/developer-relations/2015/06/salesforce-lightning-inputlookup-missing-component.html


http://sfdcmonkey.com/2017/07/17/re-usable-custom-lookup/

http://sfdcmonkey.com/2017/01/07/custom-lookup-lightning-component/

https://teamforcesite.wordpress.com/2017/09/20/how-to-build-custom-lookup-in-lightning/
https://github.com/enreeco/inputlookup

https://www.jitendrazaa.com/blog/salesforce/lookup-component-in-salesforce-lightning/

https://www.lightningdesignsystem.com/components/lookups/


What’s the difference between Einstein Article Recommendations and Suggested Articles?

How Does Einstein Article Recommendations Work? Einstein Article Recommendations helps support agents resolve customer cases efficiently by ...