I'm needing to create a simple lightning component to surface a canvas app on an account record detail page using the Lightning App Builder. Implementing force:hasRecordId, I want to use v.recordId as a parameter in <force:canvasApp developer="RBFS" parameters='{"accountId": "{!v.recordId}"}' />. I can't work out how to create an expression that will render the required JSON string for the parameters to be accepted. As per this discussion I also can only seem to pass the most simple object to the parameters attribute such as parameters='{"record": "smith"}' and have it surface in the environment.parameters field in the signed request.

I'm just starting out with salesforce and lightning components and so far I have tried:

<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" access="global" >
   <ui:outputText class="form-control" aura:id="recid" value="{!v.recordId}" />
   <force:canvasApp developerName="RBFS" parameters='{"accountId": "{!v.recordId}"}' />

But this gives an aura compile error.

Cannot mix expression and literal string in attribute value, try rewriting like {!'foo' + v.bar}

I have tried crazy escaping and string concatenation parameters="{!'\'\{\"accountId\": \"" + v.recordId + "\"\}\'}" but this produces a parsing error in the Developer console.

Can someone point out how to fix this?

Side Note:

  • I have seen that you can get record context automatically in certain situations when surfacing a canvas app in the environment.record property of the signed request. This worked for me using the equivalent canvasApp in a VisualForcePage component in Lightning App Builder using <apex:canvasApp />. This does not seem to work with <force:canvasApp /> hence why I'm attempting to pass the recordId via this method.

I am answering here with a solution that worked for me in the end in case anyone might find it useful.

Trick was to use an init handler to set the value via the controller:

<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" access="global" >
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <force:canvasApp developerName="RBFS" parameters="{!v.getRecordId}" /> 

and then in the controller:

doInit : function(cmp) {

    var recordId = cmp.get("v.recordId");
    var output = '{"record": "' + recordId + '"}';
    cmp.set("v.getRecordId", output);


This resulted in the parameters being dynamically passed as a JSON string as required.

| improve this answer | |

For me the above answer didn't work. In my case, I need to pass the parameters to my canvas app in order to set the URL to something other than the root URL specified in the connected app definition. In order to make this work with Lightning, I had to do the following:

Lightning Component:

<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" access="global">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />
    <aura:attribute name="parameters" type="String" />
    <force:canvasApp developerName="CustomerService" parameters="{!v.parameters}" />

The controller class:

    doInit: function(cmp) {
        var recordId = cmp.get("v.recordId");

        // NOTE: Lightning is very picky about quotes.
        // JSON keys and values MUST be wrapped with double quotes.
        // See: https://salesforce.stackexchange.com/questions/120473/canvas-app-in-lightning-component
        var json = '{"path": "/clinics/' + recordId + '/orders"}';
        cmp.set("v.parameters", json);

And for good measure, here's my CanvasLifecycleHandler class:

public class CustomerServiceCanvasLifecycleHandler
implements Canvas.CanvasLifecycleHandler {

    public Set<Canvas.ContextTypeEnum> excludeContextTypes(){
        Set<Canvas.ContextTypeEnum> excluded = new Set<Canvas.ContextTypeEnum>();

        // Code goes here to add items to excluded list
        // that should be excluded from Context data

        return excluded;

    public void onRender(Canvas.RenderContext renderContext) {
        String path = getCustomPath(renderContext);
        Canvas.ApplicationContext app = renderContext.getApplicationContext();

    private String getCustomPath(Canvas.RenderContext renderContext) {
        Canvas.EnvironmentContext env = renderContext.getEnvironmentContext();
        Map<String, Object> parameters = (Map<String, Object>)JSON.deserializeUntyped(env.getParametersAsJSON());
        String path = parameters.get('path').ToString();
        return path;
| 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.