Skip to main content
Dreamforce is streaming for free on Salesforce+. Watch now.

Show Charts on the Offline Mobile App

Learning Objectives

After completing this unit, you’ll be able to:

  • Implement a UIPluginV2 contract in Consumer Goods (CG) Modeler.
  • Create a global label for UIPluginV2.
  • Set up business logic methods to prepare the report data.
  • Configure cockpit cards for showing charts on the CG offline mobile app.
  • Debug errors to properly show the chart and test it on a mobile device.

Implement UIPluginV2

Fatima configures the JavaScript implementation of the UIPluginV2 contract she created to define the properties, labels, libraries, HTML, and CSS.

She opens the new contract MyCardDisplayReportUiPluginV2.uipluginv2.xml and copies the content of the UIPluginV2 snippet to the UIPluginV2 contract.

  1. In Interface, add the CompetitorRate property.
<Interface>
  <Property id="competitorRate" />
</Interface>
  1. In Labels, add the CardReportingCompetitorRate_Title label.
<Labels>
  <Label id="CardReportingCompetitorRate_Title" />
</Labels>
  1. In Libraries, add the C3JS and D3JS libraries.
<Libraries>
  <Library name="C3JS" />
  <Library name="D3JS" />
</Libraries>
  1. In the UI component HTML, define the HTML structure of UIPluginV2.
<UIComponentHTML name="UIComponentHTML"><![CDATA[
  <div class="WrappingContainer">
    <div id="Component" class="ComponentContainer">
      <div id="ChartContainer" class="GaugeChart">
        <div id="Chart"></div>
     </div>
   </div>
 </div>
]]></UIComponentHTML>
  1. In the UI component CSS, define the CSS classes.
<UIComponentCSS name="UIComponentCSS"><![CDATA[
 /* overall wrapper class to remove scroll-bar */
 .WrappingContainer {
overflow: hidden;
}
   ]]></UIComponentCSS>
  1. Set up the JavaScript implementation.
// Declarations
let config = {
  measures: [60, 90, 100],
  measureColors: [],
};


let chartReference;


const selectors = {
  chart: "#Chart",
};


// React specific Callbacks
function connectCallback() {
  renderChart();
}


function disconnectCallback() {
  if (PluginManager.helpers.isDefined(chartReference)) {
    chartReference.destroy();
  }
}


function renderCallback() {
  inputChanged();
}
function setStyles() {
  config.measureColors = [
    PluginManager.pluginConfiguration.Color15,
    PluginManager.pluginConfiguration.Color16,
    PluginManager.pluginConfiguration.Color14
  ];
}


function inputChanged() {
  if (PluginManager.helpers.isDefined(chartReference)) {
    chartReference.load({
      columns: [[PluginManager.locale.labels.CardReportingCompetitorRate_Title, PluginManager.competitorRate]],
    });
  }
}


function renderChart() {
  if (PluginManager.helpers.isDefined(PluginManager.competitorRate)) {
    //destroy chart object before setting new reference
    if (PluginManager.helpers.isDefined(chartReference)) {
      chartReference.destroy();
    }
    //set styles and colors
    if (PluginManager.helpers.isDefined(PluginManager.pluginConfiguration)) {
      setStyles();
    }
    //create chart
    chartReference = c3.generate({
      bindto: selectors.chart,
      data: {
        columns: [
          [PluginManager.locale.labels.CardReportingCompetitorRate_Title, PluginManager.competitorRate],
        ],
        type: "gauge",
      },
      gauge: {},
      color: {
        pattern: config.measureColors, // the three color levels for the percentage values.
        threshold: {
          values: config.measures,
        },
      },
      size: {
        height: 140,
      },
      tooltip: {
        show: false
      }
    });
  }
}
  1. Save your changes.
  2. Build your contracts to check for validation errors. Run sf mdl build.

Add a Global Label for UIPluginV2

After the JavaScript implementation, Fatima adds a global label for UIPluginV2. The label helps to localize the contract in different languages.

  1. Go to the $workspace/src/Locale folder.
  2. Add the label to the Global Labels.globallabel.xml contract.
<Label id="CardReportingCompetitorRate_Title" text="Competitor Rate" translationStatus="1"/>
  1. To populate the new label to all locales, run this CLI command in VS Code-based Modeler.
    sf modeler workspace refreshLocale
  2. Save your changes.

Fatima is satisfied with the implementation of UIPluginV2. She now creates business logic methods to prepare the report data.

Prepare the Report Data

In CG Modeler, UIPluginV2 is used to create business reports and charts such as the Competitor Rate chart. But how does Fatima define the data that these reports show? She prepares the report data using business logic methods.

  1. Create a business logic method. In the VS Code terminal, run sf modeler add and enter these details.
? Select the resource you want to add: Businesslogic
? Specify a name for the business logic: GetCompetitorRate
? Select the module to which the GetCompetitorRate business logic is added: MyDisplay
? Select a suitable option for the GetCompetitorRate business logic: method
? Select the reference object to add the business logic method: LoMyDisplays
  1. In the new business logic method, add this code to the jsDoc tags.
    * @returns competitorRate
  2. In the customization range, enter this code to define the Competitor Rate chart.
let competitorRate;
let competitorDisplays = 0;
competitorDisplays = me.filter(function(comp){ return comp.competitorDisplay == "1";}).length;
let Displays = me.getCount();
competitorRate = 100 * competitorDisplays / Displays;
  1. Save your changes.

Fatima has completed the first part of the UIPluginV2 setup. Next, she configures cockpit cards on the CG offline mobile app.

Configure Cockpit Cards to Show Charts

Fatima has created and implemented the UIPluginV2 contract. She can define a binding in the UI for each of the properties she specified in UIPluginV2. Next, to show the percentage of competitor products from the displayed products in a store in the Competitor Rate chart, Fatima creates a cockpit card. She integrates the UIPluginV2 contract into the cockpit card to display the Competitor Rate chart.

The CG offline mobile app UI is based around two cockpits: the User Cockpit and the Store Cockpit. The User Cockpit, or the Your Day screen, is the default landing page that a sales rep sees when they log in to the CG offline mobile app. They can review information about their visits, route maps, and app sync status on this page, which are organized into multiple cards.

The CG offline mobile app’s User Cockpit UI.

Whereas, on the Store Cockpit, sales reps can see a 360-degree view of a store, get visit-related information with in-store live reporting, and access all the visit tasks in one place.

Fatima configures a card on the User Cockpit to show the Competitor Rate custom report and charts.

  1. Add a CardContainer control called CardDisplayReport to the Card Area in the Application_CockpitUI.userinterface.xml contract.
<!-- Reporting Card START -->
<CardContainer name="CardDisplayReport">
  <Bindings>
    <Resource target="Title" type="Label" id="ReportingDislpayCardTitle" defaultLabel="Displays" />
    <Resource target="Information" type="Label" id="ReportingDisplayCardInformation" defaultLabel="Competitor Rate" />
    <Binding target="IsReadyToLoad" type="Text" binding="ProcessContext::CardDisplayReport_DataLoaded" bindingMode="ONE_WAY" />
  </Bindings>
  <VisibilityRoles allRoles="true" />
  <Events>
    <LoadContainerData event="CardDisplayReport_loadData" />
  </Events>
  <UIPluginV2 name="MyCardDisplayReportUiPluginV2" uiPlugin="MyCardDisplayReportUiPluginV2">
    <Bindings>
      <Binding target="competitorRate" type="Text" binding="ProcessContext::CardDisplayReport_CompetitorRate" bindingMode="ONE_WAY" />
    </Bindings>
  </UIPluginV2>
</CardContainer>
<!-- Reporting Card END -->
  1. Define the declarations for Competitor Rate Cockpit Card in the Application_CockpitProcess.processflow.xml contract.
<!-- Card DisplayReport -->
<Declaration name="CardDisplayReport_DisplayList" type="LoMyDisplays"/>
<Declaration name="CardDisplayReport_DataLoaded" type="DomBool"/>
<Declaration name="CardDisplayReport_CompetitorRate" type="DomDecimal" />
  1. Configure Event handler in the ShowCockpit action section of the Application_CockpitProcess.processflow.xml contract to load data to the report.
<!-- Card: DisplayReport -->
<Event name="CardDisplayReport_loadData" action="CardDisplayReport_loadData" />
  1. To load the list object and calculate the competitor rate, define the required actions in the Application_CockpitProcess.processflow.xml contract.
<!-- Card: Display Reports START-->
<Action name="CardDisplayReport_loadData" actionType="LOAD" type="LoMyDisplays" >
  <Return name="ProcessContext::CardDisplayReport_DisplayList" />
  <TransitionTo action="CardDisplayReport_getCompetitorRate"/>
</Action>
<Action name="CardDisplayReport_getCompetitorRate" actionType="LOGIC" call="ProcessContext::CardDisplayReport_DisplayList.myGetCompetitorRate">
  <Parameters/>
  <Return name="ProcessContext::CardDisplayReport_CompetitorRate" />
  <TransitionTo action="CardDisplayReport_setDataLoaded"/>
</Action>
<Action name="CardDisplayReport_setDataLoaded" actionType="LOGIC" call="Utils.identity">
  <Parameters>
    <Input name="value" value="1" type="Literal" />
  </Parameters>
  <Return name="ProcessContext::CardDisplayReport_DataLoaded" />
</Action>
<!-- Card: Display Reports END→
  1. Save your changes.

Fatima has finished configuring the cockpit card. She now tests the setup on a mobile device.

Test the Setup

After Fatima creates the Modeler workspace and generates a successful build in CG Modeler, she launches the simulator UI of the mobile app. She tests the Consumer Goods Cloud offline mobile app as it appears on a tablet or mobile phone. For more information, check out Start the Simulator App for the First Time.

Fatima can’t wait to check if the cockpit card properly shows the Competitor Rate chart on the UI.

The User Cockpit showing the Competitor Rate chart card.

Yay! The Competitor Rate chart appears as expected on the User Cockpit. It shows a 33.3% competitor rate on the Displays card. Fatima couldn’t be happier.

What if the chart doesn’t show up properly? Fatima doesn’t believe in taking chances. So, she debugs to find and fix errors in the setup.

Debug Errors

If the Competitor Rate chart doesn’t properly show up on the CG offline mobile app UI, developers such as Fatima debug to resolve the issue. Here’s how she sets up debugging.

  1. Open Developer Tools in Chrome browser.
  2. Under the Source tab, select about:srcdoc/localhost:3000/framework/UIPluginV2_MyCardDisplayReportUIPluginV2.js.
  3. Set breakpoints in the connectCallback(), disconnectCallback(), or renderCallback() function and refresh the dashboard. The execution stops on the connectCallback() function.
  4. In the console, switch to about:srcdoc.
  5. To see all properties of UIPluginV2, type PluginManager.

Fatima’s UIPluginV2 setup is now complete.

Toward the Next Frontier

In this unit, you explored how to implement UIPluginV2 and configure business logic methods to prepare the report data. You also learned how to set up a cockpit card on the CG offline mobile app to show the Competitor Rate chart. Finally, you learned how to set up debugging to find and resolve potential errors in setup.

In the next unit, discover how to create a button to open a third-party app from the CG offline mobile app UI.

Resources

Share your Trailhead feedback over on Salesforce Help.

We'd love to hear about your experience with Trailhead - you can now access the new feedback form anytime from the Salesforce Help site.

Learn More Continue to Share Feedback