In APEX, Visualforce, Lightning Components, Automation, Blog, Flow, Salesforce Lightning

URL Hack Functionality In Lightning?!

First, sorry for the click bait like blog title. Second, sorry to Shannon Hale who I’m sure still cries everytime someone uses a URL Hack.

Now a history lesson. For you young and hip kids who have never known anything besides Lightning Experience, you likely have no idea what I mean by a URL Hack. But back in my day (hitches up pants past his belly button) in Salesforce Classic you add information in the URL and change or augment the behavior of Salesforce. Common examples of URL Hacks were Creating a Contact Role at the Same time as Creating an Opportunity, Automatically selecting the To and email template when sending an email, and the classic – opening a new record page while pre-filling values.

An example of the last one would look like this: https://na14.salesforce.com/001/e?retURL=%2F001%2Fo  This is the standard classic URL for creating a new account. Looking at the HTML source of the code, I can find the name of a field, say Number of Employees and add it to the URL as a parameter. Adding &acc15=35 would pre-fill the number 35 in the Employee Number field. So thus our URL became https://na14.salesforce.com/001/e?retURL=%2F001%2Fo&acc15=35

Place this URL on a custom button and perhaps use some merge fields and you have a dynamic way to pre-fill data. This is a URL hack because we are taking the URL of Salesforce and “hacking” it to change the behavior.

Cool right? Well the problem young wippersnapper was URL hacks were never officially supported. Plus the use hard-coded HTML values. Did you just go from NA14 to NA44? Guess what? All your URL Hacks are likely broken. Did you just create a new object and URL Hacks on sandbox? Guess what? You have to update those hacks because the Name/IDs have changed. When Salesforce rolled out Lightning Experience, it prevented almost all URL hacks from working. The only support URL hack is dynamically setting a filter value on a report via the URL – and that only works on the browser and not the mobile environment.

Salesforce attempted to replace URL Hacks with quick actions. And in some circumstances, these are a great alternative. There’s something to be said to having the user go to the normal edit or create page and seeing the full page layout. With actions you have to specify the page layout and it doesn’t support sections. It’s impossible to make the pages look identical. It’s also a lot of upkeep since you have to update the page layout plus the action layout everytime you add or remove a field. Speed and response time is also an issue on actions with lots of fields. Got a big page layout and want to duplicate as an action? Be prepared for some slowness.

Actions could really only replicate the create URL Hacks. All the other URL Hacks couldn’t be addressed. It also was a poor substitute for needing a full-page layout when creating or editing. Finally, there’s one scenario where these quicks actions simply cannot handle, that URL Hacks DID handle, and where my little solution replicates with a bit more effort.

The Setup

I was using a custom object for my real-world scenario, but for universal comparison, let’s use Cases. In our world, we use tasks to remind users to create follow up Cases. How do I handle this without a URL Hack or other helpful shortcuts?

  1. As a user, I click on the “related to” of the Task to go to the Account.
  2. next I have to use the New Case or New Case Action to create the Case.
  3. I enter the Contact – which was on the Task for the Case and fill out other fields which – some which values are on the Contact or the Account
  4. Then I click save

Ick, what a crappy user experience. It’s only 4 steps, but come on. FOUR Steps! I’m too busy doing whatever I’m supposed to be doing in my job to deal with FOUR steps! We could use an action on the Account to create the case and populate some of the fields from the Account, but it wouldn’t be able to do that with the Contact. Plus, we wouldn’t get to the same layout if we use an Action. Other options include creating the case via automation and then having the user edit it – bleh. We could use Flow to query the information from the account and contact and then display a screen to capture the rest of the information or just create the case and have the user edit it afterwards. Again, Bleh I tell you!

Here’s my solution:

  1. Click a button on the Task
  2. Go to the new Case field with Account & Contact values filled in. I only have to add other items
  3. Save

Boom! I saved ONE whole step! I know you’re laughing at me. That’s only one step! Well depending on how many fields you have to fill in based on values on the Account and Contact, I just saved a lot of data entry. Plus, the user is taken to the full new case page layout. If I add or remove fields, I don’t need to update anything else.

It looks and feels very much like a URL Hack in Classic. So how do I replicate this URL Hack Functionality In Lightning?

Building a URL Hack Functionality In Lightning

To accomplish the wonderful feat, we need 3 things:

  1. An Action that calls a Flow
  2. The Flow for said Action
  3. A Custom Lightning Component

Wait, wait wait! Don’t leave! I know I said Lightning Component and everyone starts thinking “Oh that’s code, that doesn’t count.” Here’s the thing, this Lightning Component requires NO Apex code. You can easily copy and paste the examples I’ll provide and alter them and it’ll work! You just need to have My Domain enabled to use it. Plus, you can use this same Lightning Component to create other “Hack” buttons using the same object (more on that later).

Let’s take these piecces one at a time.

The Action

Using an Action to call a Flow is one of my favorite Winter ’18 Feature . This is how we’re going to call our Flow and thus our Lightning Component from the Task. Creating these actions are very simple.

  1. Go to Object Manager in Setup and select Task
  2. Select Buttons, Links, and Actions
  3. Click “New Action” button
  4. Select “Flow” as the Action Type
  5. Select your Flow
  6. Provide a name
  7. Save and add to the page layout

That’s it! So darn simple.

Salesforce Quick Action with Flow

The Flow

Here’s the second key component with this solution. Technically speaking, the Flow really only needs to call the Lightning Component. Let’s not do that because we want to make this really cool, right?

So in this example, the Flow will be fairly simple. Here’s the list of the elements in the order they “Flow.”

  1. Lookup Task: Fast Lookup to get the task. My lookup criteria is Id equal recordId. recordId is a flow variable and is where the Task ID gets stored when the user clicks on the Action
  2. Decision WhatId Object: This is a Decision Element that checks that the WhatId of the task (also known as related to) is indeed an Account. This is important since if the Task is related to an Opportunity and someone clicks to create the action, I need different elements to query for the data I need for my case. I would have a path for each object you WANT the users to create the case from.
  3. Lookup Account: Fast Lookup to get the Account and the fields I want from the Account
  4. Lookup Contact; Fast Lookup to get the Contact and the fields I want from the Contact
  5. Create Case: Lightning Component where we pass the values from Account, Contact, and anything else as attributes.

That’s it. It’s not a difficult Flow. You should have fault elements for the Fast Lookups and have an error handling screen for your Decision. I didn’t do that to keep the screenshot small. I would strongly recommend using your default outcome for the Decision element to handle scenarios when a user clicks the action and the WhatId isn’t any of the preferred objects. This way you can provide a screen to your user that states there was an error and when you want them to use the Flow.

Flow for URL Hack in Lightning

Simple Flow for URL Hack in Lightning

The Lightning Component

The Lightning Component involves NO Apex code. Which means anyone should be able to do this.

I used the Developer Console to create this Lightning Component.

Open up the developer console, click the file menu and hover over New and then select Lightning Component.

There are 3 parts this this Lightning Component. The Component, Design, and Controller. You can select these items from the menu on the right side of developer console.

Lightning Component in Developer Console

Lightning Component in Developer Console

The Component

There’s a couple of important bits in the component. The first is what is “implements.” This controls where this component can be referenced. There’s a whole list in the documentation. In this situation, we’re using just the implement to make it available as a Flow Action.

The second important bit are the attributes.  The official description is “describes an attribute available on the app, interface, component, or event.” Not all that helpful to non-developers. Think of these attributes as names for data you’re going to use in the component. In this example, I’m using just string for text values. There are a bunch of other types including Date, Decimal, and Boolean.

For my example, I chose attributes for the fields I’m going to pre-fill on the Case. I chose to use “Input*FieldName*” to keep it simple, but you can name it whatever you want. Just remember that the name will be the same in the design and will be what will show up in the Flow.

<aura:component implements="lightning:availableForFlowActions">
  <aura:attribute name="InputContactID" type="String" />
  <aura:attribute name="InputAccountID" type="String" />
  <aura:attribute name="InputType" type="String" />
  <aura:attribute name="InputOrigin" type="String" />
  <aura:attribute name="InputReason" type="String" />
  <aura:attribute name="InputSubject" type="String" /> 
</aura:component>

The Design

Design Attributes are similar to the attributes in the component. They need to be spelled the same and with the same capitalization as the Component attributes. In the design, the attributes listed are what will be exposed to tools like the App Builder or in our example Flow. Since I’m using my Attributes to set the data I want to pre-fill on the form, I’m again using the field names.

<design:component>
  <design:attribute name="InputContactID" />
  <design:attribute name="InputAccountID" />
  <design:attribute name="InputType" />
  <design:attribute name="InputOrigin" />
  <design:attribute name="InputReason" />
  <design:attribute name="InputSubject" />
</design:component>

The Controller

Finally, the Controller. This is the bit that some people may go cross-eyes and get confused. The Controller controls what the component does.  I’m going to break this down into sections.

  1. Get the values passed into the component
  2. Define what action the component will do
  3. Set the parameters for the action
  4. Fire

The first part is where you see all the “var name = component.get(“v.InputContactId”)”; This is a variable in the controller. It can be named whatever you want. The key part is component.get. This tells the controller with Attribute you want to get from the component. The format is v.AttributeName. You’ll notice in my example I choose to name my controller variable to be the Attribute name without  “Input.”

The second part defines the actions. This is the variable I call “createRecordEvent.” In this scenario I want to take the user to the create record page so I’m setting it as “$A.get(“e.force:createRecord”)” The developer documentation has what other actions you can perform.

The third part is setting the parameters for the action. So if our action is creating a record, we need to tell the component the type of record we’re creating, the record type id, if applicable, and the values for the fields. entityApiName is the object for the record. This could be “Account”, “Contact”, or for custom objects “MyCustomObjectName__c”. Next are the fields and their values. You can see in the sample the API name of the field in single quotes, followed by a colon, and ending with the variable holding the value. You don’t have to use the variable here. If the field value will always be the same you can skip the attribute for the field and simply do ‘fieldname__c’ : “Value”.

Finally, we “fire” the action” This is an important line. Everything that we’ve done so far is simply setting things up. Without firing, the create action will not occur.

That’s it for the Lightning Component!

({
 invoke : function(component, event, helper){
   var ContactID = component.get("v.InputContactID"); 
   var AccountID = component.get("v.InputAccountID"); 
   var Type = component.get("v.InputType"); 
   var Origin = component.get("v.InputOrigin"); 
   var Reason = component.get("v.InputReason"); 
   var Subject = component.get("v.InputSubject"); 

   var createRecordEvent = $A.get("e.force:createRecord");

   createRecordEvent.setParams({ 
     "entityApiName": "Case", 
     "defaultFieldValues": {
      'ContactId' : ContactID,
       'AccountId': AccountID,
       'Type': Type,
       'Origin': Origin,
       'Reason':Reason,
       'Subject':Subject
    } 
  });
  createRecordEvent.fire(); 
 }
})

Wrap up and Conclusion

There we go! Three simple items to re-create URL Hack functionality in Lightning.

Is it as simple as a URL Hack?

I think that’s up for debate. It’s more than a URL, so in that respect it’s not as simple. However, with this method there’s no trolling through HTML to find field names on the form and there’s no concern about IDs/Names changing from Instant changes or moving from Sandbox to Production. In the sense it’s is simpler.

Is there a way to do this better? Can I make it more re-usable?

Probably. But I can’t think of a way to do it now. My first attempt at this component was to make it 100% re-usable. The challenge is that Lightning Components that implement availableforFlowActions only accept certain types of attributes. If I could pass in a map or even reliably parse a string of a map or json, we could make a completely re-usable component. The part that is NOT re-useable are setting the Object (entityApiName) and the Field Values (defaultFieldVales). We could pass an attribute to pass in the object, but not to pass in the fields/values.

The only way I can think of making it a bit more reusable is putting a set cap on the number of fields. I could then have attributes like “Field1Name”, “Field1Value”, “Field2Name”,”Field2Value” and so on. But that just looks so messy. Instead I opted to create one for each object.

I still would like to make it more flexible, so please go vote on this idea: Allow non-string attribute types like Map and Object for Flow Local Actions

Finally

I hope you find this helpful and useful. Let me know how will you use this “URL Hack” in Lightning in the comments. I also love to see what other URL Hack functionality you would like to be able to do in Lightning, so please add those in the comments.

Finally, if you’re a Flownatic myself, check out our T-Shirts at our new store. Purchases help support paying for the services to host the blog and podcast. We’re an affiliate so purchasing other people’s designs after clicking our link helps us too.

Thanks for Reading.

 

P.S. Want to have fun with me being silly with a greenscreen behind me? You can grab a gif of Shock Wizard Here:

https://wizardapprentice-dev-ed.my.salesforce.com/sfc/p/j0000000KIxy/a/0a000000cwQp/JX9vr25r_1YBIDwQp5Df4rbLEwDXy61keI6eTAC1Fsg

URL Hack Functionality In Lightning

Addendum: Doug Ayers took this idea and went completely Lightning Component. No Flow included (what’s the fun in that?) Check out his Lightning Component URL Hack which includes a git hub for you to grab the code yourself!

I’ve tried this out and it does work. The only issue I’ve experienced are when users go “Back” using the browser button or through a “back” button in the component. When you are using this lightning component for multiple buttons on the same layout, the system doesn’t seem to “refresh” between button clicks when the user uses button 1, cancels or goes back and clicks button 2. Beyond that, it works really well.

Don’t miss a post! Sign up to receive email notications.

Subscribe

Subscribe to our mailing list

* indicates required
I want to receive email notifications about:

I run this site, the podcast, and my training videos for the community. I do incur some costs. I greatly appreciate if you can help me out by checking out my affiliates and – if you shop amazon – start your search on my site.

Recommended Posts
Showing 19 comments
  • Natalie Gunther
    Reply

    Hi there wizard! Can you create an example for the email template and filling in the to field? I have a custom object and I would like one button that would determine if it’s a lead buyer, select the lead buyer’s email (user look up field) and template X, or if it’s a support buyer, select the contact buyer’s email (contact look up field) and template Y.

    • Brian Kwong
      Reply

      You’re looking for a Lightning version right? Using a lightning template?

      • Natalie Gunther
        Reply

        Yes, I am in lightning. I think it could be a lightning template or a classic template – today they are classic templates, but I could probably convert them to lightning templates.

  • Eyal
    Reply

    Sorry but I missed something , why do we need lightning component to create a record and could not create it using the flow, what benefit it gives?

    • Brian Kwong
      Reply

      You could create it from the flow. The benefit is this provides the user a few options, 1. They can fill in the rest of the record including required fields that you may not be able to fill in via the flow (because you don’t know what the value should be) and 2. The user can cancel it. If you create in the flow the best you can do is then take the user to the record to then edit it. Plus you give the user access to the standard create page. There’s no partial page or having to recreate the page layout in actions or a flow screen

  • Firas
    Reply

    Brian, this trick you posted is incredible and has been a huge help in recreating url hacks where the newly created record is on the detail side of a Master-Detail relationship. I was wondering if you could help with building a component for finishing a flow. Currently we have a Close Opportunity flow with screens the user walks through and on the last step there is a finish screen with a url that takes them back to the opportunity. Using the Flow Lightning Component I have embedded this flow on a lighting page, however I want to have the last step be a local action/component that automatically refreshes or redirects the user to the opportunity record. I’ve tried the solution on this page: https://developer.salesforce.com/forums/?id=9060G0000005WRKQA2 and am getting an unknown controller action “invoke” flow error. I recently ran into this help article but have not tried it yet, https://help.salesforce.com/articleView?id=vpm_finish_override.htm&type=5.

  • Firas
    Reply

    Amaaaaaaazing, I think I will try the load webpage or redirect to url component in the local action section https://sites.google.com/view/flowunofficial/flow-local-actions?authuser=0. This is pure gold, thank you!!

  • Oscar
    Reply

    Brian- This is AWESOME! Where are there good resources to review how to set up error messages in the flow? The walk-through video was awesome! Thank you!

    • Brian Kwong
      Reply

      Thank you for the feedback Oscar.

      As to your question, it really depends on the type of Flow and the type of error message. When your Flow has screens, the best way is to put the Fault message on the screen itself (if applicable, for example when a Fault occurs on a Fast Lookup). The main benefit is you can customize the message and provide instructions to your user about what happened and what to do. So, for example, if you expect to find records and don’t, you can display a message that tells the user that no records were found and to either 1. create some or 2. put in different information.

      If your flow does not have screens and is called automatically, you’re a bit out of luck for providing nice messages to the end user. What you can do is send emails and create chatter posts. You can either hard-code the to Address for your emails, or lookup the running user and get their email. You can also post onto the record that spawned the problem – assuming the error isn’t that you don’t know the ID of the involved record. Another option is you can post to a Chatter Group but that may be a less than useful method depending upon your use case. With Chatter posts, I always recommend that you @ mention the involved user when possible.

      • Oscar
        Reply

        Thanks Brian!

        Update: I built a flow that creates a new case from an account using this process. What a life and timesaver! I know I could create a quick action but cases needed more detail filled than what was being pulled from the account. This is going to be a huge win to an overburdened team. THANK YOU!

  • Haseeb
    Reply

    Hello Brian, I am getting an error in flows “Error Occurred: c.invoke is not a function” what could be the reason?

    • Brian Kwong
      Reply

      I had this same issue. Common error is you don’t have my domain setup in your org. If my domain is there, check for case sensitive issues. In every case I had this problem is was due to my domain

  • Haseeb
    Reply

    Thank you for your reply, it is resolved now it was due to My domain was not enabled in my org. but I am seeing a Flow finished screen when I am clicking Cancel button from Record Create page

    Regards

    • Brian Kwong
      Reply

      yep. That’s just the nature of Flow being called in actions. I haven’t found a way around that.

  • Haseeb
    Reply

    Hello Brain,
    Is there any way that we can save the created record Id and use it further in flow?

    Regards

    • Brian Kwong
      Reply

      That’s a great question! I know you can specify outputs to a local action, but I’ve never actually tried it.

      • Haseeb
        Reply

        Do we need update the component as well?

        • Brian Kwong
          Reply

          In all likelihood, I think the component will need to get updated. Likely an attribute for the record ID will need to be added and something in the controller to set the value. I don’t know since I haven’t tried it yet! Unfortunately, I’m not going to have a chance to try it for some time.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Start typing and press Enter to search

Unofficial Salesforce Flow