Using Apex Services from Your Container

Use the lightning-container NPM module to call Apex methods from your Lightning container component.

To call Apex methods from lightning:container, you must set the CSP level to low in the manifest.json file. A CSP level of low allows the Lightning container component load resources from outside of the Lightning domain.

This is an Aura component that includes a Lightning container component that uses Apex services:

<aura:component access="global" implements="flexipage:availableForAllPageTypes">

    <aura:attribute access="private" name="error" type="String" default=""/>

    <div>
        <aura:if isTrue="{! !empty(v.error)}">
            <lightning:textarea name="errorTextArea" value="{!v.error}" label="Error: "/>
        </aura:if>

        <lightning:container aura:id="ReactApp"
                             src="/ApexController/index.html"
                             onerror="{!c.handleError}"/>
    </div>

</aura:component>

This is the component’s controller:

({
    handleError: function(component, error, helper) {
        var description = error.getParams().description;
        component.set("v.error", description);
    }
})

There’s not a lot going on in the component’s JavaScript controller—the real action is in the JavaScript app, uploaded as a static resource, that the Lightning container references.

import React, { Component } from 'react';
import LCC from "lightning-container";
import logo from './logo.svg';
import './App.css';

class App extends Component {

  callApex() {
    LCC.callApex("lcc1.ApexController.getAccount",
                 this.state.name,
                 this.handleAccountQueryResponse,
                 {escape: true});
  }

  handleAccountQueryResponse(result, event) {
    if (event.status) {
      this.setState({account: result});
    }
    else if (event.type === "exception") {
      console.log(event.message + " : " + event.where);
    }
  }

  render() {
    var account = this.state.account;

    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to LCC</h2>
        </div>
        <p className="App-intro">
          Account Name: <input type="text" id="accountName" value={this.state.name} onChange={e => this.onAccountNameChange(e)}/><br/>
          <input type="submit" value="Call Apex Controller" onClick={this.callApex}/><br/>
          Id: {account.Id}<br/>
          Phone: {account.Phone}<br/>
          Type: {account.Type}<br/>
          Number of Employees: {account.NumberOfEmployees}<br/>
        </p>
      </div>
    );
  }

  constructor(props) {
    super(props);
    this.state = {
      name: "",
      account: {}
    };

    this.handleAccountQueryResponse = this.handleAccountQueryResponse.bind(this);
    this.onAccountNameChange = this.onAccountNameChange.bind(this);
    this.callApex = this.callApex.bind(this);
  }

  onAccountNameChange(e) {
    this.setState({name: e.target.value});
  }
}

export default App;

The first function, callApex(), uses the LCC.callApex method to call getAccount, an Apex method that gets and displays an account’s information.