Sunday, April 10, 2016

Salesforce Lightning App - AutoTypeAhead using Generic Search (Re-usable)

Steps to Implement AutoComplete/AutoTypeAhead using Lightning Component and Generic Search Term (re-usable code for searching within any Object/Term):



1) Create My Domain. (SetUp->Domain Management->My Domain)

2) Create a class "AutoTypeAheadController" with Aura enabled method (Re-usable method for searching a term within any SObject)

3) Upload Static Resources:
a) bootstrap.min.css (Static Resource Name: BootStrapCss)
Link: http://developer.salesforcefoundation.org/bootstrap-sf1/
b) jquery-1.11.3.min.js (Static Resource Name: jqueryjs)
Link: https://jquery.com/download/
c) jquery-ui.css (Static Resource Name: jqueryuicss)
Link: https://jqueryui.com/download/all/
d) jquery-ui.min.js (Static Resource Name: jqueryuijs)
Link: https://jqueryui.com/download/all/

4) Create Lightning Component "AutoTypeAhead".

5) Create Lightning App "AutoTypeAheadApp".

6) If your Org doesnt have namespace then use the following URL to access the Lightning App:
https://<<Domain Name>>.lightning.force.com/c/AutoTypeAheadApp.app
If your Org has a namespace then use the following URL to access the Lightning App:
https://<<>Domain Name>.lightning.force.com/<<NameSpace>>/AutoTypeAheadApp.app



Code Details:

************************************************************************************************************
Class: AutoTypeAheadController
************************************************************************************************************
global class AutoTypeAheadController {
 
    @AuraEnabled
    global static SObject[] autoSearch(map<string,string> request){
    /*
        Purpose: this function will be called from the lightning component,
        This will provide search result (SOSL) for any single object.
        
        request contains the following string key-value pairs
        @find: the actual string, user would search for
        @sobject: api name of sobject in which search would occur
        @fields: csv of the api names of the field that search would return
        @where: where clause used in SOSL
        @limit: limit clause used in SOSL
        @return: the function would return list of sobject
    
        Example:
        map<String, String> request
        = new Map<String, String>
        {'find' => 'test', 'sobject' => 'Account', 'fields' => 'Id, Name', 'where' => 'Status=Active', 'limit' => 25};      
    */

        String find = String.escapeSingleQuotes(request.get('find'));
        String sobject_name = request.get('sobject');
        String fields = request.containsKey('fields')? request.get('fields') : 'Name';
        String where_clause = request.containsKey('where') ? ' WHERE ' + request.get('where') : '';
        String limit_clause = request.containsKey('limit') ? ' LIMIT ' + request.get('limit') : '';
        
        
        String sosl = 'FIND \'%STR%*\'IN NAME FIELDS RETURNING %SOBJECT% (Id, %FIELDS% %WHERE% %LIMIT%)';
        sosl = sosl.replace('%WHERE%', where_clause);
        sosl = sosl.replace('%LIMIT%', limit_clause);
        
        sosl = sosl.replace('%STR%', find).replace('%SOBJECT%', sobject_name).replace('%FIELDS%', fields);
        
        SObject[] search_result = new SObject[0];
       
        
        for(sobject s :search.query(sosl)[0]){
            if(String.valueOf(s.get('Name')).containsIgnoreCase(find)) {
                search_result.add(s);            }
        }
        return search_result;
    }
}

************************************************************************************************************
************************************************************************************************************

************************************************************************************************************
Lightning Component: AutoTypeAhead
************************************************************************************************************
*************
Component:
*************
<aura:component controller="AutoTypeAheadController" implements="flexipage:availableForAllPageTypes,force:appHostable">
    <aura:attribute name="sObjectType" required="true" type="String" description="Name of the sObject that will be filtered" />
    <aura:attribute name="fields" type="String[]" default="" description="List of fields to get with each record"/>
    <aura:attribute name="limit" type="String" default="10" description="Limits the number returned to this value" />
    <aura:attribute name="inputLabel" type="String" default="Find" description="Label for text input"/>
    <aura:attribute name="ready" type="Boolean" default="false" description="Used to check if resources have been loaded"/>

    <aura:registerEvent name="autotypeaheadEvt" type="c:autotypeaheadEvt"/>
  
    <ltng:require scripts="/resource/jqueryjs,/resource/jqueryuijs"
         styles="/resource/jqueryuicss,/resource/BootStrapCss"
        afterScriptsLoaded="{!c.init}"
    />
    <div>
        <label>Search for {!v.sObjectType}: </label>
        <input id="searchTerm" class="AutoTypeAhead" type="text" />
    </div>
</aura:component>

*************
*************

*************
Controller:
*************
({
  
    init: function(component, event, helper) {     
        if (typeof jQuery !== "undefined" && typeof $j === "undefined") {
            $j = jQuery.noConflict(true);;
        }      
      
           component.set("v.ready", true);
           helper.initHandlers(component);
    }
  
})

*************
*************

*************
Helper:
*************
({
    initHandlers: function(component) {
        var ready = component.get("v.ready");

        if (ready === false) {
               return;
        }
      
        var ctx = component.getElement();
      
        $j(".AutoTypeAhead", ctx).autocomplete({
            minLength: 2,
            delay: 500,
            source: function(request, response) {
                var action = component.get("c.autoSearch");
                var fieldsToGet = component.get("v.fields");
              
                action.setParams({
                    "request":{
                    "sobject": component.get("v.sObjectType"),
                    "find": request.term,
                    "fields": fieldsToGet.join(),
                    "limit": component.get("v.limit")}
                });
              
                action.setCallback(this, function(a) {
                    var suggestions = a.getReturnValue();
                    var responseRes = a.getState();
                    if (responseRes === "ERROR") {
                       var errors = a.getError();
                       if (errors) {
                           if (errors[0] && errors[0].message) {
                               console.log("Error message: " + errors[0].message);
                           }
                       } else {
                           console.log("Unknown error");
                       }
                    }
                    if(responseRes === "SUCCESS")
                    {
                        //console.log("Output:"+JSON.stringify(suggestions));
                        suggestions.forEach(function(s) {
                            s["label"] = s.Name,
                            s["value"] = s.Id
                        });
                    }
                    response(suggestions);
                });
              
                $A.run(function() {
                    $A.enqueueAction(action);
                });
            },
            select: function(event, ui) {
                event.preventDefault();
                var ctx = component.getElement();
                $j(".AutoTypeAhead", ctx).val(ui.item.label);
                  
                var selectionEvent = component.getEvent("autotypeaheadEvt");
                selectionEvent.setParams({
                    selectedOption: ui.item
                });
                selectionEvent.fire();
            }
        });
    }

})

*************
*************

*************
Event:
*************
<aura:event type="COMPONENT"> <aura:attribute name="selectedOption" type="Object"/></aura:event>
**************
**************

*************
Renderer:
*************
({
  
    afterRender : function(component, helper) {
        this.superAfterRender();
            helper.initHandlers(component);
    }
})

*************
*************

************************************************************************************************************
************************************************************************************************************


************************************************************************************************************
Lightning App: AutoTypeAheadApp
************************************************************************************************************

*************
Application:
*************
<aura:application implements="force:appHostable">
    <div class="container-fluid">
        <div class="jumbotron">
          <h1>Auto-Complete Lightning Component</h1>
        </div>
        <div class="row">  
        <div class="form-group text-center">
            <c:AutoTypeAhead sObjectType="Account"
                    autotypeaheadEvt="{!c.handleAutocomplete}"
                    fields="Name,AccountNumber"
                />
        </div>
        </div>
        <div id="result"></div>
    </div>
</aura:application>

*************
*************

*************
Controller:
*************
({
    handleAutocomplete : function(component, event, helper) {
        var so = event.getParam("selectedOption");
        document.getElementById("result").innerHTML = 'Selected:' + so.Name;
    }
})

*************
*************

************************************************************************************************************
************************************************************************************************************

No comments:

Post a Comment