Rendering  reactApp using the LCC npm module in a Lightning Component

The previous section gave you an idea of how to use Lightning:container. In this section, we will explore how to build an ES6 React application, and host it inside a static resource and render it inside a Lightning Component. The app creates an account by calling an Apex class method that has all the logic to do DML on the account object.

We will be using the webpack bundler to bundle all the code and create a bundle.js file that is placed in the static resource.

The directory structure of your project with SFDX is shown in the following screenshot:

Note that all the JavaScript assets will be placed under react-app/src

The static resource folder will have a reactApp folder that has index.html, slds, styles, and the manifest.json file. Note that all these are zipped. If you are using SFDX scratch Orgs, the static resource ZIP file is generated during execution of command:

sfdx force:source:push 

Let's look into the package.json file in the following code snippet:

{
"name": "react-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.4",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"webpack": "^4.5.0",
"webpack-cli": "^2.1.4"
},
"dependencies": {
" Lightning-container": "^1.0.0",
"react": "^16.3.1",
"react-dom": "^16.3.1"
}
}

Note we are using webpack, babel for transpiling, and Lightning-container.

The Lightning-container npm module (https://www.npmjs.com/package/ Lightning-container) provides APIs to call Salesforce Apex remoting methods, and also provides the ability for Lightning Components to send messages from the iframe back to the app in the static resources. 

Let's look into the webpack config file:

const webpack = require('webpack');
const path = require('path');

const config = {
mode: 'development',
entry: './src/index.js',
output: {
path: path.join(__dirname, '../force-app/main/default/staticresources/reactApp'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
}
};
module.exports = config;

The preceding code snippet takes all the sources from index.js as entries, creates a bundle.js in ES5 format using babel-loader, and places it in the staticresource/reactApp folder for the reactApp, where we have index.html and other assets for the application.

The code for the JavaScript is as follows. Note it uses ES6 classes and syntax, as well as JSX.

The index.js file is as follows:

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

ReactDOM.render(<App />, document.getElementById("app"));

The App.js file is as follows:

import React from "react";
import LCC from ' Lightning-container';

class App extends React.Component {

constructor(props) {
super(props);
this.state = {
account : {
"Name" : "",
"Phone" : "",
"Website" : "",
"Fax" : "",
},
accountId : ""
}
this.saveAccount = this.saveAccount.bind(this);
this.onAccountNameChange = this.onAccountNameChange.bind(this);
this.onAccountPhoneChange = this.onAccountPhoneChange.bind(this);
this.onAccountFaxChange = this.onAccountFaxChange.bind(this);
this.onAccountWebsiteChange = this.onAccountWebsiteChange.bind(this);
}

saveAccount(){
LCC.callApex("AccountController.saveAccount",
this.state.account,
(result, event) => {
if (event.status) {
this.setState({accountId: result.Id });
var msg = {
action: 'openDetails',
id: result.Id
};
LCC.sendMessage(msg);
console.log(result);
} else if (event.type === "exception") {
console.log(event.message + " : " + event.where);
}

},
{ escape: true });
}

onAccountNameChange(e) {
var account = Object.assign({}, this.state.account);
account.Name = e.target.value;
this.setState({account});
}

onAccountPhoneChange(e) {
var account = Object.assign({}, this.state.account);
account.Phone = e.target.value;
this.setState({account});
}

onAccountFaxChange(e) {
var account = Object.assign({}, this.state.account);
account.Fax = e.target.value;
this.setState({account});
}

onAccountWebsiteChange(e) {
var account = Object.assign({}, this.state.account);
account.Website = e.target.value;
this.setState({account});
}

render() {
return (
<div>
<div class="slds-form-element__control">
<input id="name" type="text" className="slds-input" placeholder="Enter Account Name..." value={this.state.account.Name} onChange={e => this.onAccountNameChange(e)}/>
</div>
<div class="slds-form-element__control">
<input id="phone" type="text" className="slds-input" placeholder="Enter Account Phone..." value={this.state.account.Phone} onChange={e => this.onAccountPhoneChange(e)}/>
</div>
<div class="slds-form-element__control">
<input id="fax" type="text" className="slds-input" placeholder="Enter Account Fax..." value={this.state.account.Fax} onChange={e => this.onAccountFaxChange(e)}/><br/>
</div>
<div class="slds-form-element__control">
<input id="website" type="text" className="slds-input" placeholder="Enter Account Website..." value={this.state.account.Website} onChange={e => this.onAccountWebsiteChange(e)}/><br/>
</div>
<br/>
<button className="slds-button slds-button_brand" onClick={this.saveAccount}>Create Account</button>
</div>
);
}

}

export default App;

Observe how we use the Lightning-container npm module's methods to call the Apex method and send messages to the component.

The Lightning Component markup and the JS controller code are as follows:

<aura:component access="global" implements="flexipage:availableForAllPageTypes">
<div class="slds-align_absolute-center">
Create Account App
</div>
< Lightning:container aura:id="jsApp" src="{!$Resource.reactApp + '/index.html'}" onerror="{!c.handleError}" onmessage="{!c.handleMessage}"/>
</aura:component>

The controller code is as follows:

({
handleMessage: function (component, event, helper) {
var message = event.getParams();
var navigationEvent = $A.get("e.force:navigateToSObject");
navigationEvent.setParams({
"recordId": message.payload.id,
"slideDevName": "details"
});
navigationEvent.fire();
},

handleError: function (component, event, helper) {
var error = event.getParams();
console.log(error);
}
})

To build the bundle for the React application, use the following command:

npm build

To push the entire code to the scratch Org, run the following command. Note that this command automatically takes care of creating a static resource ZIP file from the static resource folder:

sfdx force:source:push

The preceding section assumes you are familiar with the React framework (https://reactjs.Org/).

Note that the principles discussed in this section apply to Angular, Vue.js, or any other framework.

The methods provided by the Lightning-container npm module are described in the following table:

Method Description
LCC.sendMessage(message)

Sends a message to the hosting Lightning Component.

LCC.addMessageHandler(handler)

Registers a listener for messages sent by the hosting Lightning Component.

LCC.removeMessageHandler(handler)

Removes a listener for messages sent by the hosting Lightning Component.

LCC.callApex(method, params, callback, config)

Calls a method in an Apex controller.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.204.186