[SalesForce] Lightning Custom component not working in Visualforce Page

I'm using a custom lightning component in an app and that app is being used in a VF page, I have created a component for look up thing, since we dont have any standard components/tags for that, And this custom component is working fine when used out side page, Cant figure out where i'm wrong, Any help is appreciated.

VF Page

    <apex:page standardController="Traffic__c" sidebar="false" showHeader="false" standardStylesheets="false">

    <apex:includeLightning />

    <div id="lightning"/>
<div id="lightning2"/>
    <script>

        $Lightning.use("c:createNewTraffic", function() {
            $Lightning.createComponent("c:CreateTraffic",
                  {},
                  "lightning2",
                  function(cmp) {
                    // do some stuff
              });
        });   
            $Lightning.use("c:createNewTraffic", function() {
            $Lightning.createComponent("c:AccountLookup",
                  {},
                  "lightning",
                  function(cmp) {
                    // do some stuff
              });
        });
    </script>
</apex:page>

App:

<aura:application access="GLOBAL" extends="ltng:outApp">
     <aura:dependency resource="c:CreateTraffic" /> 
    <aura:dependency resource="c:AccountLookup" />  
</aura:application>

AccountLookup.cmp:

<!-- Event handlers -->
<aura:handler name="updateLookupIdEvent" event="c:UpdateLookupId" action="{!c.handleAccountIdUpdate}"/>
<aura:handler name="clearLookupIdEvent" event="c:ClearLookupId" action="{!c.handleAccountIdClear}"/>

<!-- Lookup component -->
<c:LookupSObject label="Account" pluralLabel="Accounts" sObjectAPIName="Account"
    listIconSVGPath="/resource/SLDSv0122/assets/icons/standard-sprite/svg/symbols.svg#account"
    listIconClass="slds-icon-standard-account"
/>

AccountLookupController.js :

({
    /**
     * Handler for receiving the updateLookupIdEvent event
     */
    handleAccountIdUpdate : function(cmp, event, helper) {
        // Get the Id from the Event
        var accountId = event.getParam("sObjectId");

        // Set the Id bound to the View
        cmp.set('v.recordId', accountId);
    },

    /**
     * Handler for receiving the clearLookupIdEvent event
     */
    handleAccountIdClear : function(cmp, event, helper) {
        // Clear the Id bound to the View
        cmp.set('v.recordId', null);
    }
})

LookUpSobject.cmp :

<aura:component controller="LookupSObjectController" implements="force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId" access="global">
    <!-- Required Scripts/Styles -->
    <!-- Salesforce Lightning Design System : https://www.lightningdesignsystem.com/ -->
    <ltng:require styles="/resource/SLDSv0122/assets/styles/salesforce-lightning-design-system-ltng.css" />

    <!-- Attributes -->
    <aura:attribute name="sObjectAPIName" type="String" required="false"
        description="The API name of the SObject to search" />
    <aura:attribute name="label" type="String" required="false"
        description="The label to assign to the lookup, eg: Account" />
    <aura:attribute name="pluralLabel" type="String" required="false"
        description="The plural label to assign to the lookup, eg: Accounts" />
    <aura:attribute name="listIconSVGPath" type="String" default="/resource/SLDSv0122/assets/icons/custom-sprite/svg/symbols.svg#custom11"
        description="The static resource path to the svg icon to use." />
    <aura:attribute name="listIconClass" type="String" default="slds-icon-custom-11"
        description="The SLDS class to use for the icon." />
    <aura:attribute name="searchString" type="String"
        description="The search string to find." />

    <!-- Events -->
    <aura:registerEvent name="updateLookupIdEvent" type="c:UpdateLookupId"/>    
    <aura:registerEvent name="clearLookupIdEvent" type="c:ClearLookupId"/>    

    <!-- Lookup Markup : See https://www.lightningdesignsystem.com/components/lookups -->
    <div class="slds"> 
        <div aura:id="lookup-div" class="slds-lookup" data-select="single" data-scope="single" data-typeahead="true">
            <!-- This is the Input form markup -->
            <div class="slds-form-element">
                <label class="slds-form-element__label" for="lookup">{!v.label}</label>
                <div class="slds-form-element__control slds-input-has-icon slds-input-has-icon--right">
                    <c:svg class="slds-input__icon" xlinkHref="/resource/SLDSv0122/assets/icons/utility-sprite/svg/symbols.svg#search" />
                    <!-- This markup is for when an item is currently selected -->
                    <div aura:id="lookup-pill" class="slds-pill-container slds-hide">
                        <span class="slds-pill slds-pill--bare">
                            <span class="slds-pill__label">
                                <c:svg class="{!'slds-icon ' + v.listIconClass + ' slds-icon--small'}" xlinkHref="{!v.listIconSVGPath}" />{!v.searchString}
                            </span>
                            <button class="slds-button slds-button--icon-bare" onclick="{!c.clear}">
                                <c:svg class="slds-button__icon" xlinkHref="/resource/SLDSv0122/assets/icons/utility-sprite/svg/symbols.svg#close" />
                                <span class="slds-assistive-text">Remove</span>
                            </button>
                        </span>
                    </div>
                    <!-- This markup is for when searching for a string -->
                    <ui:inputText aura:id="lookup" value="{!v.searchString}" class="slds-input" updateOn="keyup" keyup="{!c.search}" />
                </div>
            </div>
            <!-- This is the lookup list markup. Initially it's hidden -->
            <div aura:id="lookuplist" class="slds-lookup__menu slds-hide" role="listbox">
                <div class="slds-lookup__item">
                    <button class="slds-button">
                        <c:svg class="slds-icon slds-icon-text-default slds-icon--small" xlinkHref="/resource/SLDSv0122/assets/icons/utility-sprite/svg/symbols.svg#search" />
                        &quot;{!v.searchString}&quot; in {!v.pluralLabel}
                    </button>
                </div>
                <ul aura:id="lookuplist-items" class="slds-lookup__list" role="presentation">
                </ul>
            </div>
        </div>
    </div>

</aura:component>

LookUpSobjectController.js :

({
    /**
     * Search an SObject for a match
     */
    search : function(cmp, event, helper) {
        helper.doSearch(cmp);        
    },

    /**
     * Select an SObject from a list
     */
    select: function(cmp, event, helper) {
        helper.handleSelection(cmp, event);
    },

    /**
     * Clear the currently selected SObject
     */
    clear: function(cmp, event, helper) {
        helper.clearSelection(cmp);    
    }
})

LookUpSobjectHelper.js :

     ({
    /**
     * Perform the SObject search via an Apex Controller
     */
    doSearch : function(cmp) {
        // Get the search string, input element and the selection container
        var searchString = cmp.get("v.searchString");
        var inputElement = cmp.find('lookup');
        var lookupList = cmp.find("lookuplist");
        var lookupListItems = cmp.find("lookuplist-items");

        // Clear any errors and destroy the old lookup items container
        inputElement.set('v.errors', null);
        lookupListItems.set('v.body', new Array());

        // We need at least 2 characters for an effective search
        if (typeof searchString === 'undefined' || searchString.length < 2)
        {
            // Hide the lookuplist
            $A.util.addClass(lookupList, 'slds-hide');
            return;
        }

        // Show the lookuplist
        $A.util.removeClass(lookupList, 'slds-hide');

        // Get the API Name
        var sObjectAPIName = cmp.get('v.sObjectAPIName');

        // Create an Apex action
        var action = cmp.get("c.lookup");

        // Mark the action as abortable, this is to prevent multiple events from the keyup executing
        action.setAbortable();

        // Set the parameters
        action.setParams({ "searchString" : searchString, "sObjectAPIName" : sObjectAPIName});

        // Define the callback
        action.setCallback(this, function(response) {
            var state = response.getState();

            // Callback succeeded
            if (cmp.isValid() && state === "SUCCESS")
            {
                // Get the search matches
                var matches = response.getReturnValue();
                console.log('--matches---');
                console.log(matches);
                // If we have no matches, return
                if (matches.length == 0)
                {
                    return;
                }

                // Render the results
                this.renderLookupComponents(cmp, lookupListItems, matches);
            }
            else if (state === "ERROR") // Handle any error by reporting it
            {
                var errors = response.getError();

                if (errors) 
                {
                    if (errors[0] && errors[0].message) 
                    {
                        this.displayToast('Error', errors[0].message);
                    }
                }
                else
                {
                    this.displayToast('Error', 'Unknown error.');
                }
            }
        });

        // Enqueue the action                  
        $A.enqueueAction(action);                
    },

    /**
     * Render the Lookup List Components
     */   
    renderLookupComponents : function(cmp, lookupListItems, matches)
    {
        // list Icon SVG Path and Class
        var listIconSVGPath = cmp.get('v.listIconSVGPath');
        var listIconClass = cmp.get('v.listIconClass');

        // Array of components to create
        var newComponents = new Array();

        // Add a set of components for each match found
        for (var i=0; i<matches.length; i++)
        {
            // li element
            newComponents.push(["aura:html", {
                "tag" : "li",
                "HTMLAttributes" : {
                    "class" : "slds-lookup__item"
                }
            }]);

            // a element
            newComponents.push(["aura:html", {
                "tag" : "a",
                "HTMLAttributes" : { 
                    "id" : cmp.getGlobalId() + '_id_' + matches[i].SObjectId, 
                    "role" : "option", 
                    "onclick" : cmp.getReference("c.select") 
                }
            }]);

            // svg component
            newComponents.push(["c:svg", {
                "class" : "slds-icon " + listIconClass + " slds-icon--small",
                "xlinkHref" : listIconSVGPath
            }]);

            // output text component
            // For some reason adding an aura:id to this component failed to record the id for subsequent cmp.find requests
            newComponents.push(["ui:outputText", {
                "value" : matches[i].SObjectLabel
            }]);
        }

        // Create the components
        $A.createComponents(newComponents, function(components, status) {
            // Creation succeeded
            if (status === "SUCCESS")
            {
                // Get the List Component Body
                var lookupListItemsBody = lookupListItems.get('v.body');

                // Iterate the created components in groups of 4, correctly parent them and add them to the list body
                for (var i=0; i<components.length; i+=4)
                {
                    // Identify the releated components
                    var li = components[i];
                    var a = components[i+1];
                    var svg = components[i+2];
                    var outputText = components[i+3];

                    // Add the <a> to the <li>
                    var liBody = li.get('v.body');
                    liBody.push(a);
                    li.set('v.body', liBody);

                    // Add the <svg> and <outputText> to the <a>
                    var aBody = a.get('v.body');
                    aBody.push(svg);
                    aBody.push(outputText);
                    a.set('v.body', aBody);

                    // Add the <li> to the container
                    lookupListItemsBody.push(li);
                }

                // Update the list body
                lookupListItems.set('v.body', lookupListItemsBody);
           }
           else // Report any error
           {
                this.displayToast('Error', 'Failed to create list components.');
           }
        });

    },

    /**
     * Handle the Selection of an Item
     */
    handleSelection : function(cmp, event) {
        // Resolve the Object Id from the events Element Id (this will be the <a> tag)
        var objectId = this.resolveId(event.currentTarget.id);

        // The Object label is the 2nd child (index 1)
        var objectLabel = event.currentTarget.children[1].innerText;

        // Log the Object Id and Label to the console
        console.log('objectId=' + objectId);
        console.log('objectLabel=' + objectLabel);

        // Create the UpdateLookupId event
        var updateEvent = cmp.getEvent("updateLookupIdEvent");

        // Populate the event with the selected Object Id
        updateEvent.setParams({
            "sObjectId" : objectId
        });

        // Fire the event
        updateEvent.fire();

        // Update the Searchstring with the Label
        cmp.set("v.searchString", objectLabel);

        // Hide the Lookup List
        var lookupList = cmp.find("lookuplist");
        $A.util.addClass(lookupList, 'slds-hide');

        // Hide the Input Element
        var inputElement = cmp.find('lookup');
        $A.util.addClass(inputElement, 'slds-hide');

        // Show the Lookup pill
        var lookupPill = cmp.find("lookup-pill");
        $A.util.removeClass(lookupPill, 'slds-hide');

        // Lookup Div has selection
        var inputElement = cmp.find('lookup-div');
        $A.util.addClass(inputElement, 'slds-has-selection');

    },

    /**
     * Clear the Selection
     */
    clearSelection : function(cmp) {
        // Create the ClearLookupId event
        var clearEvent = cmp.getEvent("clearLookupIdEvent");

        // Fire the event
        clearEvent.fire();

        // Clear the Searchstring
        cmp.set("v.searchString", '');

        // Hide the Lookup pill
        var lookupPill = cmp.find("lookup-pill");
        $A.util.addClass(lookupPill, 'slds-hide');

        // Show the Input Element
        var inputElement = cmp.find('lookup');
        $A.util.removeClass(inputElement, 'slds-hide');

        // Lookup Div has no selection
        var inputElement = cmp.find('lookup-div');
        $A.util.removeClass(inputElement, 'slds-has-selection');
    },

    /**
     * Resolve the Object Id from the Element Id by splitting the id at the _
     */
    resolveId : function(elmId)
    {
        var i = elmId.lastIndexOf('_');
        return elmId.substr(i+1);
    },

    /**
     * Display a message
     */
    displayToast : function (title, message) 
    {
        var toast = $A.get("e.force:showToast");

        // For lightning1 show the toast
        if (toast)
        {
            //fire the toast event in Salesforce1
            toast.setParams({
                "title": title,
                "message": message
            });

            toast.fire();
        }
        else // otherwise throw an alert
        {
            alert(title + ': ' + message);
        }
    }
}) 

When used inside the app:
lookup cmp, Working as expected

LookUp Inside app

When used in a page:
lookup cmp, Not working

Inside VF page

Best Answer

I was having similar issue where it would show "loading" icon when the component was embedded in VF page. See this post: force:inputField does not work in lightning component rendered on VF page

And to Itai's comment, please post concise code which will resolve it faster.

Related Topic