Best way to incorporate Visual Flows?

  • 2
  • Question
  • Updated 6 months ago
  • Answered
We need users to be able to access visual flows (Flows) from our pages. What is the best method to incorporate them?
Photo of Thaddeus Ward

Thaddeus Ward

  • 736 Points 500 badge 2x thumb

Posted 6 years ago

  • 2
Photo of Zach McElrath

Zach McElrath, Employee

  • 53,814 Points 50k badge 2x thumb
I have removed my previous answer about using a Visualforce Page Include --- this is NOT recommended as an approach, as it only works for single-screen Flows (i.e. it's not a viable option at all).

If Flows (Visual Workflows) need to be included within Skuid Pages (it's always good to consider whether this is in fact necessary) then the recommended way to do this is to include your Flow via an iFrame, using Skuid's Template Component.

Simple Flows - no parameters

This is actually very easy to do. If your Flow does not expect to be handed any input variables, then the syntax for including a Flow called "MyFlow" via an iFrame is basically just:



<iframe src="/flow/My_Flow" width="100%" height="400px" frameborder=0/>



To use this in a Skuid Page, just drag a Template Component into the workspace, copy and paste in the above iFrame line, swapping out "My_Flow" for the Unique Name of your Flow, and setting the height to be a value appropriate for the size of your Flow (e.g. if your Flow's screens are really long, you'll need to increase height to something like 1400px, etc.

On your Template Component, make sure to check "Allow HTML", and ordinarily, you should check "Do not run template on each row".

Passing Parameters into your Flow

If you need to pass parameters into your Flow to set some Variables, this is as simple as modifying the iFrame src URL to pass in a Query String parameter for each Variable you need to populate in your Flow. Just add a Query String parameter for each Variable name --- the parameter names need to match the names of the Variables in your Flow, exactly.

For our example, we'll use a Flow that creates a new "Scholarship Request" record for a particular Contact. For this Flow, we would probably need one or more of the following pieces of information passed in to our Flow: a College Application Id, and/or a Contact Id. For the sake of example, let's assume that we want to pass in both of these pieces of information into our page. Basically, here's what the content of the Skuid Template Component looks like:



<iframe src="/flow/New_Scholarship_Flow?applicationId={{{$Model.Application.data.0.Id}}}&contactId={{{$Model.ContactData.data.0.Id}}}" width="100%" height="800px" frameborder="0"></iframe>



Let's break down our iFrame's src attribute.


  • Our Flow's Unique Name was New_Scholarship_Flow.

  • We pass in an applicationId attribute corresponding to a Variable of that name within our Flow. For its value, we go to a Model in our Skuid Page called "Application", and go into the first row in its data (data.0 gets the first row, data.1 would get the second row, etc.), and pull the "Id" field --- the Application's Id.

  • We pass in an contactId attribute corresponding to a Variable of that name within our Flow. For its value, we go to a Model in our Skuid Page called "ContactData", and go into the first row in its data, and pull the "Id" field --- the Contact's Id.

  • Notice that we use the Triple-mustaches for our merges, e.g. {{{ and }}} instead of {{ and }}. In general when interacting with URLs within Templates (here, our iFrame's src attribute), it's always good to use Triple-mustaches, so that no Skuid Rendering logic is run on the Merged-fields. Otherwise the iFrame HTML could get interrupted and not work properly.




Here's what our Flow looks like, from the Builder. Notice that we have Variables called applicationId and contactId, both with their "Type" property set to "Input Only". This allows Query String Parameters passed in to our Flow to be used to populate these Variables when the Flow starts up:







Here's what our Skuid Page looks like from the Builder:



And here's what the Page looks like in action. We've placed our New Scholarship Flow within a Tab in a Tabset. Notice that the "Supplied Contact Id" and "Supplied Application Id" areas, inside of our Flow, have been populated with the applicationId and contactId of the Application and Contact record in our Skuid Page's Models:



After we fill out the two required textareas in our Form, we can click Next --- this does a Record Create operation that creates a new Scholarship_Request__c record, and if the save is successful, we're shown a success page with the Id of our newly-created Scholarship Request record:



From here, the user can click Finish to start the Flow over again.
Photo of Thaddeus Ward

Thaddeus Ward

  • 736 Points 500 badge 2x thumb
Excellent . This looks viable for us. Currently we are passing in variables directly from the object where the button link is located. It looks like we need to redirect the variable declarations to reference the model instead. Not a big deal.

Many thanks.
Photo of Zach McElrath

Zach McElrath, Employee

  • 53,814 Points 50k badge 2x thumb
Thaddeus, see my reply below --- it is not necessary to use the longer $Model syntax to get access to variables. If your Template model is set appropriately, you can use a shortcut.
Photo of Zach McElrath

Zach McElrath, Employee

  • 53,814 Points 50k badge 2x thumb
A note on merge syntax here: it is NOT necessary to use the {{$Model.ModelName.data.0.FieldName}} syntax to pass variables into Template components --- however, this syntax will universally work.

There is a shortcut that works if all /some of the variables you need to pass in are accessible through the Template Component's Model. In our scenario, if we had set our Template Component to be on the Application Model, and we UNCHECKED the "Do not run template on each row", then we could leverage Row-level merge variables for our Application Model's first row to pass in the Application's Id and the Contact Id, because Contact__c is a field on our Application record, reducing our Template Component to the following:



<iframe src="/flow/New_Scholarship_Flow?applicationId={{{Id}}}&contactId={{{Contact__c}}}" width="100%" height="800px" frameborder="0"></iframe>



***NOTE***: with this syntax, it is essential to use triple-mustaches, {{{ and }}} , instead of {{ and }}, to stop Skuid from running its standard Field rendering logic on these Fields. If you do not use the triple mustaches, it won't work.
Photo of Thaddeus Ward

Thaddeus Ward

  • 736 Points 500 badge 2x thumb
Almost there, but for some reason I can't get my one and only variable declared.

I am trying what you suggest in this last post because my template is set on the model where the right data field is, and it is the first row in the model, but the variable keeps showing up blank.

Photo of Zach McElrath

Zach McElrath, Employee

  • 53,814 Points 50k badge 2x thumb
You need to uncheck "Do not run template on each row". That will fix it. If you have this checked, then the Template is run in "Model" context --- and so Row-specific Merge variables, such as the Id field, will not be processed.
Photo of garrett.zaino

garrett.zaino

  • 204 Points 100 badge 2x thumb
Hey Zach - I'm trying to invoke a flow from a button action. I need to pass variables into the flow. We reference the sObject itself - rather than a specific field or ID because it saves a query of the database. Is there syntax to pass the entire model to the flow as opposed to a specific field?
Photo of Zach McElrath

Zach McElrath, Employee

  • 53,814 Points 50k badge 2x thumb
Hey Garrett, I definitely understand the desire to avoid a query in the flow, but it's unfortunately not straightforward to send the row to the Flow via input variables. However, it should be possible using a JavaScript snippet, if you're comfortable doing that I could probably suggest an approach.
Photo of garrett.zaino

garrett.zaino

  • 204 Points 100 badge 2x thumb
Awesome - thanks Zach. I've updated my flow to accept the Id and query if additional info is not included as an alternative invocation method.
Photo of Zach McElrath

Zach McElrath, Employee

  • 53,814 Points 50k badge 2x thumb
So, full disclosure, I haven't tried this, as I don't have a Flow setup in my dev environment right now that expects an SObject as a parameter, but here's the basic idea, if you're interested in going down a rabbit hole that may prove frustrating and may not work ;)

First, I'd move the "Run Data Source Action" call that invokes the Flow into a distinct Action Sequence. Then, you could define a named Input on the Action Sequence called "sobject" or something like that. Then, use this syntax to provide a value for that parameter when invoking the action. Let's say your Flow variable name is "theSObject", then the Value to put in would be "{{$Input.sobject}}". 

Now, you just need to invoke this Action Sequence using a JavaScript Snippet. Here's how you could do this:


var myModel = skuid.model.getModel("MyModel");
var myRow = myModel.getFirstRow();

// Here, define the SObject. Only send along the fields that you actually need for your Flow,
// but make sure to include the Id field so that Salesforce can identify the SObject.
var rowAsSObject = {
    Id: myRow.Id,
    Some_Other_Field__c: myRow.Some_Other_Field__c,
};

// Find the Skuid Action Sequence by name, and run it, passing in a value for the "sobject" parameter.
// Other parameters could be passed in as well by modifying the namedInputs object.
// NOTE: you could also invoke it by unique id using getById(uniqueId), if you prefer.

var namedInputs = {
   sobject: rowAsSObject
};

return skuid.actionSequences.getByName("Run my flow").run(namedInputs);