1

For the last month or so, I have been trying to come up with a way to convert a Javascript button to a Lightning component/action without much success.

Currently the button we have uses the following code:

{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")} 
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")} 
var result = sforce.apex.execute("orderOutput","generate", {genericId:"{!Opportunity.Id}"}); 
window.alert(result ); 
window.location.reload(true);

This button uses a piece of Apex code in the background that basically allows us to generate a text EDI order that another system picks up and manipulates.

The code in the background looks like this:

global class orderOutput {

    webservice static String generate(Id genericId) {
        Set<String> validSObjects = new Set<String>();
        validSObjects.add('Opportunity');

        String result;        
        String sObjectType = genericId.getSObjectType().getDescribe().getName();

        if (sObjectType == 'Opportunity') {
            result = generateFromOpportunity(genericId);
        } else {
            result = 'Error: Generate called for unsupported SObject Type ' + sObjectType + '\r\n\r\nValid SObject Types are:\r\n';
            for (String soType: validSObjects)
                result += soType + '\r\n';
        }

        return result;
    }

    private static String generateFromOpportunity(Id opId) {

        system.debug('***************************** generateFromOpportunity(Id opId) *********************************');
        system.debug('opId : ' + opId);

        String result;

        List<Opportunity> validateList = new List<Opportunity>([SELECT Id FROM Opportunity WHERE Id = :opId AND Customer_Number__c != null AND Delivery_Customer_State_Province_updated__c != null AND Delivery_Customer_City__c != null AND Delivery_Customer_Name__c != null AND Delivery_Customer_Post_Code__c != null AND Delivery_Customer_State__c != null]);

        if(validateList.isEmpty()) {

            result = 'Error: Required fields missing.\r\n\r\nCustomer Number, Customer Name, Delivery Customer Address 3, Delivery Customer City, Delivery Customer Post Code and Delivery Customer State/Province are required for Output Order.';

        } else {

            date todaysDate = date.today();
            List<Order_Output__c> ooDelete = new List<Order_Output__c>([SELECT Id FROM Order_Output__c WHERE Opportunity__c = :opId AND Order_Date__c = :todaysDate]);
            if (!ooDelete.isEmpty())
                delete ooDelete;

            List<Order_Output__c> ooList = new List<Order_Output__c>();

            List<Opportunity> oList = new List<Opportunity>([SELECT Id, Order_Output__c, (SELECT Id, Order_Output__c, PricebookEntry.Product2.Name, Quantity, LastModifiedDate FROM OpportunityLineItems WHERE Quantity > 0) FROM Opportunity WHERE Id = :opId]);

            system.debug('oList : ' + oList);     

            if(!oList.isEmpty()) {

                //get snapshot qtys
                List<AggregateResult> aList = new List<AggregateResult>([SELECT OLI__c, SUM(Qty__c) FROM Order_Output__c WHERE Opportunity__c = :opId GROUP BY OLI__c]);
                Map<Id, Integer> oliMap = new Map<Id, Integer>();
                for(AggregateResult a : aList) {
                    oliMap.put(String.valueOf(a.get('OLI__c')), Integer.valueOf(a.get('expr0')));
                }

                Opportunity o = oList[0];
                system.debug('o.OpportunityLineItems : ' + o.OpportunityLineItems);

                if(!o.OpportunityLineItems.isEmpty()) {

                    Order_Output__c ooh = new Order_Output__c();
                    ooh.Opportunity__c = o.Id;
                    ooh.Output__c = o.Order_Output__c;
                    ooh.Order__c = 1;
                    ooh.Order_Date__c = System.Today();

                    system.debug('Adding ooh to ooList(line 148)');
                    ooList.add(ooh);

                    Order_Output__c oo;

                    for(OpportunityLineItem oli : o.OpportunityLineItems) {

                        system.debug('oli : '+ oli);

                        system.debug('oli.LastModifiedDate: ' + oli.LastModifiedDate);
                        //system.debug('maxOutputOrderDate: ' + maxOutputOrderDate);

                        //if (oli.LastModifiedDate > maxOutputOrderDate || maxOutputOrderDate == null) {

                            Integer Qty = Integer.valueOf(oli.Quantity);

                            if(oliMap.get(oli.Id) != null){
                                system.debug('oliMap.get(oli.Id) == null');
                                Qty = Qty - oliMap.get(oli.Id);
                            }

                            if(Qty > 0) {

                                system.debug('Quantity is greater than zero');

                                oo = new Order_Output__c();

                                oo.Opportunity__c = o.Id;
                                oo.Output__c = oli.Order_Output__c.replaceAll('\\{QTY}', String.valueOf(Qty)+'.0000');
                                oo.Order_Date__c = System.Today();
                                oo.Product_Name__c = oli.PricebookEntry.Product2.Name;
                                oo.Qty__c = Qty;
                                oo.OLI__c = oli.Id;

                                system.debug('Adding oo to ooList (line 174)');
                                ooList.add(oo);

                            }

                        //}

                    }

                }

            }

            insert ooList;

            result = ooList.Size() + ' Order Lines Outputted';

        }

        return result;

    }


}

How can I convert this across?

The button is only used within the Opportunity object to create an EDI for products that have been added.

As an example, I have worked through the following: https://lightning.accorto.com/support/discussions/topics/1000081937

And have been able to get it working to an extent but the code used creates a pop-up page that doesnt format correctly. Within the page the buttons do work so I got half way there.

I have also tried working through the following: https://andyinthecloud.com/2013/07/16/how-to-call-apex-code-from-a-custom-button/

  • where is your button used currently? where is it that you will be using it that you want to have a lightning component do the same functionality? there is no magical solution to converting existing buttons to work in lightning. First things firts, you want to learn either by reading the docs or/and doing Trailheads. you might want to post your attempted approaches as well and specify the issues you are encoutnering – glls Nov 30 '17 at 0:03
  • The button is only used within the Opportunity object to create an EDI for products that have been added. As an example, I have worked through the following: lightning.accorto.com/support/discussions/topics/1000081937 And have been able to get it working to an extent but the code used creates a pop-up page that doesnt format correctly. Within the page the buttons do work so I got half way there. I have also tried working through the following: andyinthecloud.com/2013/07/16/… – Raymond A Nov 30 '17 at 0:43
  • mind updating your post with the above? – glls Nov 30 '17 at 1:16
  • I have updated my original – Raymond A Nov 30 '17 at 1:38
1

Winter'17 Has introduced Great feature to use a Lightning Component from an Action
More Details can be found here Lightning Alternatives to JavaScript Buttons

You need to pass parameters which you are passing using custom JavaScript button using lightning component attributes.
Component Attributes

Your Apex Class orderOutput has Method generate which accepts Id genericId which is OpportunityId as I can understand from your code

var result = sforce.apex.execute("orderOutput","generate", {genericId:"{!Opportunity.Id}"}); 


I am giving you example to pass OpportunityId from Lightning component as per your need you can pass multiple parameters by defining attributes inside Lightning component.

You can use force:hasRecordId to pass OpportunityId to your Apex Controller.
Other Interfaces you can implement are:

implements="force:appHostable,flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,forceCommunity:availableForAllPageTypes,force:lightningQuickAction"

force:lightningQuickAction, has been added to the platform to indicate that your component supports Actions

Add the force:hasRecordId interface to a Lightning component to enable the component to be assigned the ID of the current record. The current record ID is useful if the component is used on a Lightning record page, as an object-specific custom action or action override in Lightning Experience or the Salesforce app, and so on. This interface has no effect except when used within Lightning Experience, Salesforce app, and template-based communities.

Create Lightning Component.

<aura:component controller="YourApexController" implements="force:hasRecordId,force:lightningQuickAction" access="global" >
    <!-- Define Attribute For Current recordId -->
    <aura:attribute name="recordId" type="Id" />
    <!-- Define Attribute To Open Pop-up --> 
    <aura:attribute name="yesNoOptions" type="boolean" default="false"/>

    <!--- Display Pop-Up For Yes/No Option To Perform Your Action. --> 
    <aura:if isTrue="{!v.yesNoOptions}">
      <div role="alertdialog" tabindex="-1" aria-labelledby="prompt-heading-id" aria-describedby="prompt-message-wrapper" class="slds-modal slds-fade-in-open slds-modal--prompt">
         <div class="slds-modal__container">
            <div class="slds-modal__header slds-theme--success slds-theme--alert-texture">
               <h2 class="slds-text-heading--medium" id="prompt-heading-id">Heading As per Your Choice</h2>
            </div>
            <div class="slds-modal__content slds-p-around--medium">
               <div>
                  <p>Header For Your Model Pop-up Box</p>
               </div>
            </div>
            <div class="slds-modal__footer slds-theme--default">
               <!-- If User Clicks Yes Then Call Controller Action.-->
               <button class="slds-button slds-button--brand" onclick="{!c. functionaName}">Yes</button>
                <!-- If User Clicks No Then Close Pop-up.-->
               <button class="slds-button slds-button--brand" onclick="{!c.closeMessage}">No</button>
            </div>
         </div>
      </div>
      <div class="slds-backdrop slds-backdrop--open"></div>
    </aura:if>
    <!-- Add Component Description -->
        <div class="slds-m-around--medium" >
           <div class="slds-container--medium">
            <div class="slds-form--stacked">
              <div class="slds-form-element">                
                Add Description here which will explain What this component is About <br/>
              </div>
              <div class="slds-form-element">                
                  <!---Button Which Will Open Pop-up--> 
                  <button class="slds-button slds-button--brand" style="margin-
                          left: 39%;" onclick="{!c.openDialog}">Your Button Name</button>

              </div>
              <br/>              
            </div>
        </div>
    </div>   
</aura:component>

Your Lightning Component Controller , you can do following to get OpportunityId

     //This is method of your Component controller
     functionaName : function(component, event, helper) {
         //get Opportunity Record Id
         var getOpportunityId = component.get("v.recordId");

         helper.yourHelperFunctionName(component,getOpportunityId );

     },

     //When User Clicks on Your Button inside Componet, this will open 
      //Dailog with Yes/No Option, you can configure buttons and name of buttons as per your choice.
     openDialog: function(component, event, helper) {
         component.set("v.yesNoOptions", true);        
     },

     //Hide Dailog Box by setting attribute to false 
     closeMessage: function(component, event, helper) {       
        component.set("v.yesNoOptions", false);        
     },

Send parameter to your Apex Controller, You can pass multiple parameters as per your need, I am just giving you one example, for that you need to define attributes with datatypes in your Lightning Component.

yourHelperFunctionName: function(component,getOpportunityId ) {
        //Call Your Apex Controller Method.
        var action = component.get("c.yourApexControllermethod");
        // set Opportunity RecordId to yourApexController method, parameter name should be exact match as that of apex method parameter name.   
        action.setParams({
            'genericId': getOpportunityId 
        });

        action.setCallback(this, function(response) {
            var state = response.getState();
                if (state === "SUCCESS") {
                    //Do Something
                } else {
                    //Do Something
                }
            }            
        });
        $A.enqueueAction(action);


    },

Now in Your Apex Controller, you need to add @AuraEnabled annotation to your Apex Method.
AuraEnabled Annotation

 public class YourApexClass {
     @AuraEnabled
    public static String yourApexControllermethod (Id genericId) {
         //Do Something , you have your OpportunityId here
           //As parameter list goes up, you need to add parameters here "," seperated
    }
}
  1. You can add Lightning component on Opportunity Record page using Lightning App builder.
  2. Another Option is You can create New Action and attach Lightning Component it.
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.