When Salesforce is life!

Month: September 2015

[Salesforce / Lightning] Create your own Lightning Progress Bar

This is a repost from the article I wrote for the Salesforce Developer Blog.

Have you ever wanted a progress bar in your linghtning app?
I have and so I came up with a simple bootstrap library wrap up.

Following the successful Lightning series, I’m going to show you how I’ve made a simple Lightning Component out of the awesome Bootstrap library Bootstrap Progressbar (see details in the project’s home page).

For those who are in a TL;DR mode, here is the Github repository with the full code of the component and the demo app.

Let’s start with the component signature:

<c:ProgressBar 
 name="pb1" 
 valueMin="0"
 valueMax="1000"
 value="500"
 displayText="center"
 usePercentage="true"
 barContainerClass="progress-striped active" 
 barClass="progress-bar-info" 
 transitionDelay="10"
 displayText="center"/>

These are the attributes we can set:

  • name: name of the progress bar. This is used to ease events management
  • valueMin: bar minimum value, defaulted to 0
  • valueMax: bar maximum value, defaulted to 100
  • value: starting progress bar value
  • displayText: position of current value’s text (center or fill), blank for no text
  • usePercentage: shows the a % value text or value/max
  • barContainerClass: class of the container of the progress bar: this gives a style (leave blank for no additional effect, “progress-striped” for a “stripped” decoration and “active” to get a move)
  • barClass: this is to be applied to the bar, following the Bootstrap style (progress-bar-info, progress-bar-danger, progress-bar-warning, progress-bar-success, progress-bar-primary)
  • transitionDelay: delay in ms for the animation

This is an example of what you’ll see (simply use the provided app at https://YOUR_INSTANCE.lightning.force.com/c/ProgressBarApp.app):

The component uses 2 kind of events:

  • ProgressBarActionEvt: this is an event used to command the progress bar
  • ProgressBarMessageEvt: this is an event that is used by the progress bar to alert that the MIN/MAX values has been reached

ProgressBarActionEvt

<aura:event type="APPLICATION" description="Inbound event to guide the progress bar" >
    <aura:attribute name="value" type="Integer" default="" 
                    description="Value of the event"/>
    <aura:attribute name="name" required="true" type="String" 
                    description="Progress bar name"/>
 <aura:attribute name="action" required="true" type="String" 
                    description="Progress bar action"/>
</aura:event>

ProgressBarMessageEvt

<aura:event type="APPLICATION" description="Outboud event to guide the progress bar" >
    <aura:attribute name="value" type="Integer" default="" 
                    description="Value of the event"/>
    <aura:attribute name="name" required="true" type="String" 
                    description="Progress bar name"/>
 <aura:attribute name="message" required="true" type="String" 
                    description="Progress bar message"/>
</aura:event>

Both messages are really similar. Both have a name attribute to understand which progress bar should trap / fire the event, and a value attribute that has the value of the event.
The ProgressBarActionEvt has an action parameter that could have the following values:

  • Increment: increment by the value passed
  • Decrement: decrement by the value passed
  • FullFill: fullfills the progress bar
  • Reset: resets progress bar’s value
  • SetValue: sets a specific value

The app calls these actions in its controller’s button functions:

//...
increment10_p1 : function(component, event, helper) {
 helper.sendMessage("Increment","pb1",10);
},
//...

And in its helper:

({
 sendMessage : function(message,name,value) {
  var incrementEvt = $A.get("e.c:ProgressBarActionEvt");
        incrementEvt.setParams({
            name: name,
            value: value,
            action: message
        });
        incrementEvt.fire();
 }
})

On the other side, when we want to handle a message from the progress bar to the container app, we attach a handler to the event:

<aura:application>
    <aura:handler event="c:ProgressBarMessageEvt" 
                  action="{!c.handleProgressBarEvent}" />
 <!-- ... -->
 <div id="{!globalId+'_msg'}" />
//...
handleProgressBarEvent  : function(component, event, helper){
 var originName = event.getParam("name");
 var message =  event.getParam("message");
 document.getElementById(component.getGlobalId()+'_msg')
   .innerHTML = message+" event for progress bar named '"+originName+"' at "+(new Date()).toLocaleString();
},
//...

So every time a ProgressBarMessageEvt event is fired, the apps catches it and write down some of its info into the given DIV HTML component.

Finally let’s see how the component is constructed.
First we need to load jQuery and Bootstrap libraries and the required stylesheets:

<aura:component >
 <ltng:require scripts="/resource/BootstrapSF1/js/jquery-2.1.1.min.js,
             /resource/BootstrapSF1/bootstrap320/js/bootstrap.min.js,
             /resource/BootstrapProgressbar/bootstrap-progressbar.min.js"
        styles="/resource/BootstrapSF1/bootstrap320/css/bootstrap.min.css,
                /resource/BootstrapProgressbar/bootstrap-progressbar.min.css"
     afterScriptsLoaded="{!c.onInit}"/>
 
 <aura:handler event="c:ProgressBarActionEvt" action="{!c.handleEvent}" />
 <aura:registerEvent name="progressBarMsgEvt" type="c:ProgressBarMessageEvt"/>
 
 <!-- ... -->

And then define the place where the Bootstrap Progressbar will be drawn:

<!-- ... -->

<div class="{!'progress '+v.barContainerClass}">
 <div id="{!globalId+'_progbar'}" class="{!'progress-bar '+v.barClass}" 
   role="progressbar" 
   data-transitiongoal="{!v.value}"
   aria-valuemin="{!v.valueMin}"
   aria-valuemax="{!v.valueMax}"></div>
</div>

<!-- ... -->

This component will be fully configured by the “onInit” function of the component’s controller (that is called once all JS/CSS files are loaded):

//...
onInit : function(component, event, helper) {
        $("[id='"+component.getGlobalId()+"_progbar']")
        .progressbar({
            display_text: 'center',
            transition_delay: component.get('v.transitionDelay'),
            refresh_speed: component.get('v.refreshSpeed'),
            display_text: component.get('v.displayText'),
            use_percentage: component.get('v.usePercentage'),
            done : function(cmp){
                $A.run(function(){
                    if(component.get("v.value") >= component.get("v.valueMax")){
                        var evt = $A.get("e.c:ProgressBarMessageEvt");
                        evt.setParams({
                            name: component.get("v.name"),
                            message: "MaximumReached",
                            value: component.get("v.value")
                        });
                        evt.fire();
                    }
                    if(component.get("v.value") <= component.get("v.valueMin")){
                        var evt = $A.get("e.c:ProgressBarMessageEvt");
                        evt.setParams({
                            name: component.get("v.name"),
                            message: "MinimumReached",
                            value: component.get("v.value")
                        });
                        evt.fire();
                    }
                });
            }
        });
    },
//...

The done handler of the progress bar is used to fire the ProgressBarMessageEvt when the bar reaches min o max values.

handleEvent is the controller’s function that handles an incoming action event:

//...
 handleEvent : function(component, event, helper){
        var targetName = event.getParam("name");
        if(targetName !== component.get("v.name")) return;
        var targetIncrement = event.getParam("value");
        var action = event.getParam("action");
        var value = component.get("v.value");
        if(action === 'Decrement') value -= targetIncrement;
        else if(action === 'Increment') value += targetIncrement;
        else if(action === 'FullFill') value = component.get("v.valueMax");
        else if(action === 'Reset') value = component.get("v.valueMin");
        else if(action === 'SetValue') value = targetIncrement;

        var pb = $("[id='"+component.getGlobalId()+"_progbar']");

        if(value = component.get("v.valueMax")){
            value = component.get("v.valueMax");
        }
        component.set("v.value",value);
        pb.attr("data-transitiongoal",value).progressbar();
        
    },
//...

It simply checks progress bar name’s, action, value and executes the corresponding action.

The last command “redraws” the progress var with the new value, and executed the animation.

This is an example of fully javascript components you can make wrapping up existing javascript plugins.

Enjoy this component and may the Force.com be with you!

[Salesforce / Trailhead / Winter16] The Lightning fever: follow the trailhead!

Excited about the latest Lightning Experience announcement?

Me too but unfortunately it was published when I was on vacations without any internet connection, that’s why I read it days after its release, but I just thought “WOW!”.

with great power comes great responsibility, and the guys at Salesforce.com knows it, so they created some cool Trailhead modules to get you started, whether you are a developer, admin or a user.

Learn about why and how you can migrate to the new Lightning Experience, which are the differences and enhancements that has been made.

Watch the new Setup menu in action, saless tools, reporta and dashboards, customize the User interface and plan your rollout strategy: you can even decide which user will be using the new Lightning experience!

These set of modules are useful to understand user management, reports and dashboard creation, app customization (layouts, objects, fields) all with the new Lightning Experience interface.

If you are an experienced Salesforce.com admin you may find some of these modules way too easy, but I bet you’ll still find some new feature you didn’t know/expect!

Developers! That’s what we (most of us?) are!

These modules help you dig into the Lightning Experience as a developer: how can you use the Lightning Components? Is Visual Force dead (don’t worry, the answer is NO)?
The best feature IMHO? The Lightning Design System, finally a unique set of styles and HTML components to build custom applications with a look and feel that is consistent with Salesforce core features — without reverse engineering Salesforce styles!

…Without reverse engineering Salesforce styles!!!!

Finally some cool hints for users and how to use the new Lightning Experience interface (standard objects, list views appearance, dashboards, reports and feeds).

Next step (as usual)?

[Salesforce / Lightning Connect] Lightning Connect Custom Adapters and MongoDB

This is a repost of the article I published on Salesforce Developer Blog.

Summer ’15 Platform Release brought us the awesome Lightning Connect Custom Adapters: you can connect to external data sources and use them as custom Salesforce Objects writing custom Apex code.

After I read Introducing Lightning Connect Custom Adapters by Lawrence McAlpin, I wanted to get my hands dirty and try to implemented my own version of the adapter thinking of a “pseudo-real” use case.

If you are a TL;DR person, here is the code:

  1. Salesforce classes
  2. heroku-crest MondoDB NodeJS proxy

At first the DataSource namespace documentation has been published here, this way you can understand all the objects / interfaces / methods we’ll be using in this example.

In my use case we have:

  • A MongoDB server which stores several invoices
  • A NodeJS server that proxies Salesforce / MongoDB hosted on Heroku
  • A Custom Adapter implemented in Salesforce

The Data Model

An external system writes invoices records on the MongoDB server, storing data on the invoices table, following the model (you can simulate it by POST requesting on the following Heroku REST service):

{
    "_id": "55abc13dad230b03001d7edf",
    "contractid": "C20150001",
    "accountid": "ACC20150001",
    "created": "2013-10-25T20:15:45.851Z",
    "amount": 1000,
    "description": "invoice #1"
}

Where:

  • contractid: is a custom external id for the Contract object
  • accountid: is a custom external id for the Account object
  • _id: MongoDB id
  • created: is the created date (date/time field)
  • amount: is the amount of the invoice (number)
  • description: is a generic description

MongoBD REST interface

The next step is to give MongoDB a REST interface.
I’ve changed an old Project by Ricard Fredin, adding support for:

  • Basic authentication
  • Environment variables for MongoDB host name and port
  • Added support for $oid, $date and $regex BSON types
  • Support for Heroku Button

This is the updated repository with all the infos of the current changes and original project of the new Heroku Crest project.

This project comes with an Heroku Button:

Deploy

This means you can easily deploy this MongoDB proxy on your personal Heroku account:

You need to set your app name, the host name and the server port.

Let’s populate the DB

The last thing to do is to create at least one database on your MongoDB server with one valid user (with at least read permissions) and one table.

In our example we have a “lighthningconnect” database with an “invoices” table.

To see if your Heroku app works, make a get request:

GET https://[YOUR_HEROKU_APP_NAME].herokuapp.com/lighthningconnect/invoices
   Headers: 
   Authorization: BASIC [BASE64(username:password)]

You can also use POST/PUT/DELETE methods.

To populate your instance, make a post request of this kind:

POST https://[YOUR_HEROKU_APP_NAME].herokuapp.com/lighthningconnect/invoices
   Headers: 
     Authorization: BASIC [BASE64(username:password)]
     Content-Type: application/json

BODY:

{
    "contractid": "C20150001",
    "accountid": "ACC20150001",
    "created": {"$date" : "2014-09-15T20:12:42Z"},
    "amount": 1230,
    "description": "invoice #X"
  }

Once the MongoDB REST interface is set up, we are gonna create a new Salesforce Named Credential: this way we can setup access to the REST server (and MongoDB server) with a simple configuration on the interface, every time we make a callout to this endpoint:

The Lightning Custom Adapter implementation

The whole code of the Salesforce implementation can be found here.

The implementation is similar to the one of Lawrence McAlpin’s post.

The main modification involves the handling of the named credential and MongoDB database and table names.

Open the MongoDBDataSourceConnection.cls file and change the first lines:

private static String NC_NAME = 'MongoDB'; //Name of the Named Credential
   private static String DB_ENDPOINT_NC = 'callout:'+NC_NAME+'/lighthningconnect/invoices'; //database and table name in your own database

If you want to change the mappings, you can do it easily by modifying the following map:

private static Map FIELD_MAP = new Map{
         'Id' => '_id',
            'ExternalId' => '_id',
            'DisplayUrl' => '_id',
            'Account' => 'accountid',
            'Contract' => 'contractid',
            'CreatedDate' => 'created',
            'Amount' => 'amount',
            'Description' => 'description'
    };

And the sync() method:

override global List sync() {
        List tables = new List();        
        List columns = new List();
        
        // Always declare these two fields.
        columns.add(DataSource.Column.text('ExternalId', 255));
        columns.add(DataSource.Column.url('DisplayUrl'));
        
        columns.add(DataSource.Column.text('Description', 255));
        columns.add(DataSource.Column.text('Contract', 255));
        columns.add(DataSource.Column.text('Account', 255));
        columns.add(DataSource.Column.number('Amount', 16, 2));
        columns.add(DataSource.Column.get('CreatedDate','Created Date','', true, true, DataSource.DataType.DATETIME_TYPE, 255,0,null,null));
        
        tables.add(DataSource.Table.get('MongoDB_Invoice', 'ExternalId', columns));
        return tables;
    }

Finally we can analize how the query is really done using the REST proxy we just installed on Heroku:

private List<Map> execQuery(string soqlQuery) {
        List<Map> rows = new List<Map>();
        HttpRequest request = new HttpRequest();
        request.setEndpoint(DB_ENDPOINT_NC+soqlQuery);
        request.setHeader('Content-Type','application/json');
        request.setMethod('GET');
        request.setTimeout(60000);
        Http h = new Http();
        HttpResponse response = h.send(request);
        if(response.getStatusCode() != 200){ 
            return new List<Map>();
        }
        
        List result = (List)JSON.deserializeUntyped(response.getBody());
        for(Object obj : result){
            Map jsonObject = (Map)obj;
            Map row = new Map();
            row.put('Amount',jsonObject.get('amount'));
            row.put('Description',jsonObject.get('description'));
            row.put('Contract',jsonObject.get('contractid'));
            row.put('Account',jsonObject.get('accountid'));
            row.put('CreatedDate',parseDateTime(String.valueOf(jsonObject.get('created'))));
            row.put('ExternalId', jsonObject.get('_id'));
            row.put('DisplayUrl', DB_ENDPOINT+'/'+jsonObject.get('_id'));
            rows.add(row);
        }
        return rows;
    }

Basically we do a GET HTTP callout to our endpoint (the Named Credentials will work as a charm to authenticate user) and parse the result to create the object that will be used to present the query result.

The getSoqlQuery() method has been modified from Lawrence’s implementation, in order to adhere to the Heroku Crest application requirements (a JSON input query): we support all basic filters and result ordering.

Configure the Data Source

Once we have uploaded the two  classes, we can configure the External Data Source:

Click on the Validate and Sync button to get the new External Object named MongoDB_Invoice.

Configure the External Object’s lookups

Next step is to link this External Object to actual Account and Contract records referenced by the “contactid” and “accountid” fields on the “invoices” table.

For this reason we will create two new fields on the Account:

and Contract standard objects:

Then we can change the Contract__c and Account__c fields on the MongoDB_Invoice__x external object to be indirect lookups: follow this article but you have to change the field types of both fields type to be Indirect Lookup instead of External Lookup.

This is what you get after changing field types:

This way each record of type MongoDB_Invoice__x that have a “Contact__c” field equal to Contact.MongoDB_Ext_ID__c will be linked to the Contract as if it were a standard lookup field (the same happens for the Account object).

Use the External Object on your app

Next step, create a new custom tab for the MongoDB_Invoice__x object (I’ve configured the “All” list view to show all fields):

You can sort all columns (here the Created Date field):

Click on an External ID value you get all object info:

Where the account:

And its related lists:

And the contract:

With its related lists:

Query External Objects

Finally there is an example of a complex query:

You can certanly improve this implementation and add better query handling, speaking as a pure developer, it’s been a real funny implementation. Can’t wait to see DML statements to be added as well!

Stay tuned for the next platform releases!

Powered by WordPress & Theme by Anders Norén