Tuesday, November 28, 2017

Customize Salesforce App Navigation Menu to have SObject item on Top

Salesforce mobile App, formerly known as Salesforce1, provides you with limited options regarding customization of the menu item. You can only add the following items:
  • Salesforce productivity items such as Dashboards, Reports, Tasks, ...
  • Smarch Search Items
  • Visualforce tabs
  • Lightning Page tabs
The rest of the menu depends on the tabs you are allowed to interact and view on your Salesforce. Most of them would be Standard and Custom objects. And according to what Application you have opened, the mobile app will have the same menu.


But sometimes we would like some of our Object menu to be on top in the main menu instead in the recent section. Also to be able to interact as if it was the standard view.
This can easily be done with a few lines of code and some configuration. For this example, we shall use the Opportunity object.

First, we need to create a Lightning Component. We shall name it "OpportunityMenu". Below are the code needed. Change the "scope" according to the SObject you want.

Now we need to add a new Lightning Component Tab.

Once the custom tab has been created, we can configure the Salesforce mobile Navigation menu and add the Opportunity menu.

Reload your Salesforce App and voila..


Standard Listview layout appears

Additional Resources:
({ navHome : function (component, event, helper) { var homeEvent = $A.get("e.force:navigateToObjectHome"); homeEvent.setParams({ "scope": "Opportunity" }); <aura:component implements="force:appHostable"> <aura:dependency resource="markup://force:navigateToSObject" type="EVENT"/> <aura:handler name="init" value="{!this}" action="{!c.navHome}"/> </aura:component>

Wednesday, November 22, 2017

Uploading multiple files with the Salesforce Lightning file upload Component (Winter 18)

Salesforce has recently released the lightning:fileUpload component which is basically a file uploader for uploading and attaching files to records.

The provides an easy and integrated way for users to upload multiple files. The file uploader includes drag-and-drop functionality and filtering by file types.

For now, it is available only in beta. It will prevent us from writing complex code and as such, does not come with limitations such as heap sizes, problems with assigning permissions to custom devs.

Here are some preview of the component: 
lightning:fileUpload component layout





You can deploy the component to your Salesforce by clicking on the button below:


And source code is available at: https://github.com/kevanmoothien/lightning-file-uploader


Unfortunately, it only uploads files and for those who still want to use attachment, here is one of my previous blog on how it can be achieved. 

Saturday, November 18, 2017

Rendering Visualforce pages with Lightning Experience Stylesheets

winter-18-logoWith the latest release (Winter 18) of Salesforce, a new feature has been added to help style a Visualforce page to Lightning Design with only a single attribute to add on the apex:page xml tag. It will only be viewable under Lightning Experience or on the Salesforce app (formerly known as Salesforce1). If viewed on Salesforce Classic, the styling won't work.

Add the attribute LightningStylesheet and Salesforce get the work done for you.

Here is a sample page I made to illustrate the changes in Salesforce Classic and Lightning Experience.

Salesforce Classic 

Lightning Experience
Salesforce Classic with Inputs

Lightning Experience with Inputs

Note:

  • This is a beta version of the feature. It is still under development by the Salesforce team. 
  • You can also use the apex:slds tag for creating custom component
  • It is only available in the Winter 18 api (41). You will have this error with older api version: "Unsupported attribute lightningstylesheets in <apex:page>"

Additional Resources:
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/vf_dev_best_practices_slds_lightningstylesheets.htm


Tuesday, May 16, 2017

Automatic package license assignment to Users

We have been asked by one of our customer at SharinPix if it was possible to assign Licenses to newly created user automatically and removing the license on user upon deactivation. The solution that I was asked to do was a trigger. But this solution requires coding which will require a test class, changeset for deployment, giving user permission to execute the trigger which it quite a lot to do. In case something is wrong with the trigger, we will be required to modify on the customer sandbox and deploying again, which is kind of tedious. 

But recently I did a module on Trailhead about Process Automation which explain how to achieve complex logic without having the need to write a single piece of Apex Code. It is only by configuring Flows and Process Builders. 

Here is the solution for the above requirement

The following objects will be used to automate assigning user license: 

Below are the steps to create a Flow and Process Builder.

Flow


1. Go to Setup, Search Flows from the Quick Find textbox
2. Click on New Flow, the Flow Designer will open. 
On the left sidebar, click on the tab Resources. Create two variables var_UserId of type text and var_isNew which will store the package license id and the user id. See screenshot below. 

Variable User Id

Variable IsNew
Create a third variable of type SObject variable. Name is SharinPixLicense and Object Type is PackageLicense.

SharinPix License sobject variable

3. We now need to retrieve the Id of the license for the SharinPix package. Drag and drop a Record Lookup element to the canvas. Enter a name and insert the following properties: 
  • Look up: PackageLicense
  • Field: NamespacePrefix, Operator: 'equals', Value: 'sharinpix' (The namespace prefix of the package: Setup | Build | Installed Packages)
  • Variable assignment 
    • Field: Id, Variable: '{!SharinPixLicense.Id}'
    • Field: AllowedLicenses, Variable: '{!SharinPixLicense.AllowedLicenses}'
    • Field: UsedLicenses, Variable: '{!SharinPixLicense.UsedLicenses}'





4. Drag and drop the Record Create element to the canvas. Enter a name and insert the following properties: 
  • Create: UserPackageLicense
  • Field: PackageLicenseId, Value: {!SharinPixLicense.Id}
  • Field: UserId, Value: {!var_UserId} 
Assign license to user


Now that we have the create record, we now need to have the delete license equivalent

5. Drag and drop the Record Delete element. Enter a name and the following properties
  • Delete: UserPackageLicense
  • Field: UserId, Value: {!var_UserId} 
  • Field: PackageLicenseId, Value: {!SharinPixLicense.Id}
Remove license from user

6. Let's create the logic and assemble all the component. 
Drag and drop the Decision element on the canvas. Enter a name and create two outcomes
  • Outcome 1 
    • Name: Created
    • Resource: {!var_isNew}, Operator: equals, Value: {!$GlobalConstant.True}
    • Resource: {!SharinPixLicense.UsedLicenses}, Operator: less than, Value: {!SharinPixLicense.AllowedLicenses}
Note: I have added the condition that Used licenses should be less than Allowed Licenses in order for the flow not to crash if all licenses have been used. 
  • Outcome 2
    • Name: Deleted
    • Resource: {!var_isNew}, Operator: equals, Value: {!$GlobalConstant.False}



7. Link the component same as in the image below and set the Record Lookup as the start of the flow (click on the green arrow icon)
Wrap everything

8. Save your Flow with a name, select type Autolaunched Flow and activate it once done. 
Save flow

Process Builder


Now that our flow is completed. We need to trigger the flow and we will use a process builder to do that.

1. Go to Setup | App Setup | Create | Workflows & Approvals | Process Builder
Click on the New button, Enter the Process Name and API Name and click on Save button.
New Process

2. We need to trigger the process on a specific Object. For this, click on Add Object and in the properties, select User and select when a record is created or edited. Click on Save.
Entry criteria

3. Next step is to add the Process Criterias. In our case, we will have two criteria. One will cater for new user and the other one for user which has been deactivated.
  • Let's create the first one. Click on Add Criteria
    • Criteria Name: User is active
    • Select Formula evaluates to true
    • In the formula field, insert the following formula
      • ( ISNEW() && [User].IsActive ) || ( ISCHANGED([User].IsActive) &&  [User].IsActive )
Save the criteria
New user active or update a user to active

  • Let's create the first one. Click on Add Criteria
    • Criteria Name: User is not active
    • Select Formula evaluates to true
    • In the formula field, insert the following formula
      • ( ISCHANGED([User].IsActive) && NOT( [User].IsActive ))
Save the criteria 


4. Now we add the actions for each criteria. 
For the User is active criteria. In the Intermediate Action section, click Add Action with the following properties:
  • Action Type: Flows
  • Action name: Create License
  • Flow: Automatic Package License assignment (Yours may be under a different name)
  • Set Flow Variables
    • Flow Variable: var_UserId, Type: Reference, Value: [User].Id
    • Flow Variable: var_isNew, Type: Boolean, Value: True

5. Let's repeat step 4 for the User is not active criteria. Change the Action Name to Delete License and set the flow variable var_isNew to False.

Your process builder should look like below. 
Finally, Click on Activate to enable it. 



Every new user shall be affected a License to the package and user being deactivated will have their license removed. 

Do not hesitate to contact me in case something is missing or needs improvements. 

Cheers :)

Monday, May 15, 2017

Upload attachment on Salesforce without having heap size limit exceeded

Have you ever had a form for uploading attachments on your Visualforce page but had to restrict it to file size limit so as not to exceed Salesforce heap size governor limit?

Well this limit can be override to a maximum of 25 megabytes instead of around 3 megabytes using apex controller. It also support multiple upload at once.

Here is how I have achieved it.
Integrate the following code to your visualforce page. Basically to just need to replace the variable 'PARENT_ID' and maybe change the listener of the 'input' if yours have a different selector. 


Document of size 9 mb has been uploaded.


Attachment being created on the Contact record.


Hope it helps. Cheers!!
``` html
<apex:page >
    <apex:includeScript value="https://code.jquery.com/jquery-2.2.4.js"/>
    <script>
    jQuery(document).ready(function($) {
        $('input').on('change', function(e){
            for (var i = 0; i < this.files.length; i++) {
                uploading += 1;
                upload_file(this.files[i], PARENT_ID, function(err, res){ //pass the parentId here
                    if (uploading === uploaded){
                        console.log('uploaded'); //your operation once finish
                    }
                })
            }
        });
        var uploading = 0;
        var uploaded = 0;
        var upload_file = function(file, parentId, callback) {
            filetoBase64(file, function(err, content){
                var attachment_object = {
                    parentId: parentId,
                    Body: content,
                    Name: file.name,
                    ContentType: file.type
                };
                $.ajax({
                    url: '/services/data/v38.0/sobjects/Attachment',
                    data: JSON.stringify(attachment_object),
                    type: 'POST',
                    processData: false,
                    contentType: false,
                    headers: {'Authorization': 'Bearer {!$Api.Session_ID}', 'Content-Type': 'application/json'},
                    xhr: function(){
                        var xhr = new window.XMLHttpRequest();
                        //Upload progress
                        xhr.upload.addEventListener("progress", function(evt){
                            if (evt.lengthComputable) {
                                var percentComplete = evt.loaded / evt.total;
                                //Do something with upload progress
                            }
                        }, false);
                        return xhr;
                    },
                    success: function(response) {
                        uploaded += 1;
                        console.log(response); // the id of the attachment
                        callback(null, true)
                    }
                });
            })
        }
     
        var filetoBase64 = function(file, callback){
            var reader = new FileReader();
            reader.onload = function() {
                var fileContents = reader.result;
                var base64Mark = 'base64,';
                var dataStart = fileContents.indexOf(base64Mark) + base64Mark.length;
                fileContents = fileContents.substring(dataStart);
                callback(null, fileContents);
            }
            reader.readAsDataURL(file);
        }
    });
    </script>
    <input type="file" multiple="multiple"/>
</apex:page>
```

Saturday, April 1, 2017

Detect if visualforce is inline on a page layout from its apex controller

This tutorial will explain to you on how to detect if a visualforce page is embedded inside of a detail page layout.

To be able to detect if a VF is being on a page layout in an inline section from a custom apex controller. The following code needs to be implemented. You can tweak around the code to mean your requirement.


Moreover you can use the very same Visualforce to override buttons like "New" and "Edit" so that you can have only one Visualforce page to for different operation like creation of a new record or editing the record.

public class CheckState {
    public String vfMode {get; set;}
    private Map<String, String> urlparams = new Map<String, String>();
    public CheckState(ApexPages.StandardController std){
        urlparams = ApexPages.currentPage().getParameters();
        if (urlparams.get('id') == null){
            vfMode = 'New';
        } else if (urlparams.get('id') != null & urlparams.get('retURL') != null) {
            vfMode = 'Edit';
        } else if (urlparams.get('id') != null & urlparams.get('retURL') == null){
            vfMode = 'View';
        }
    }
}

Saturday, February 18, 2017

Retrieve Salesforce custom label dynamically in Apex

Ever wonder if it is possible to retrieve custom labels dynamically but not sure whether it is possible? Well, the answer is yes. You can retrieve custom labels dynamically.

Here is how you can achieve it. You just need to integrate the following code in  your apex class.

Hope you like it. Cheers!
public static String getLabelString(String labelName ){ Component.Apex.OutputText output = new Component.Apex.OutputText(); output.expressions.value = '{!$Label.' + labelName + '}'; return String.valueOf(output.value); }

Tuesday, February 14, 2017

Using Salesforce standard modal in a Detail page button - Part 1

Tired of having to use window.open in a detail page button to display a popup? Or using JavaScript libraries to display a modal?
Well, there is a more simple way to display a popup and this without embedding any JavaScript library in the code.

This can be achieved by using Salesforce standard modal and by tweaking the code, many things can be achieved.

To get started, Create a Custom button on the object you want the modal to be used.
Set the properties to:
Display Type: Detail Page Button
Behavior: Execute JavaScript
Content Source: OnClick JavaScript

custom button salesforce

In the JavaScript code editor, add the following code and change the variables inside it accordingly to your specification.

Here is the final result:

Check out part 2. We shall discuss how to integrate Visualforce pages inside the modal.

Cheers! :)
(function() { var width = 700; var height = 200; var title = "Dialog title here"; var box = new SimpleDialog("salesforce" + Math.random(), true); box.setTitle(title); box.displayX = true; box.isMovable = false; box.createDialog(); box.setWidth(width); // set your html content here box.setContentInnerHTML( "<h2>Your html content here</h2>" ); //set the height of the modal box.dialog.children[1].style.height = height + 'px'; box.show(); //if displayX is set to true, then override standard close event by this code box.dialog.getElementsByClassName('dialogClose')[0].onclick = function() { box.hide(); // you can add code to reload the page or redirect to another page }; //optional : add this to close the modal onclick of the overlay background box.background.addEventListener('click', function() { box.hide(); }); })();

Using Salesforce standard modal in a Detail page button - Part 2

As illustrated in Part 1, we looked at opening the modal which come with Salesforce and changing its content.

But most of the time, you want the content in the JavaScript detail button to be dynamic. So instead of writing a lot of JavaScript code and encoding the HTML content into a string to then pass it to the setContentInnerHTML function, we could display a Visualforce page.

You just need to modify it as below and change the source (src attribute).
box.setContentInnerHTML(
  '<iframe src="/apex/modaldemo" style="border:none;" width="100%" height="'+ (height - 30)+'px" />'
);

We have now added a Visualforce page, which is kind of awesome. But what if we want to some processing and at the end close the modal from within the Visualforce page?

Well, this is not possible since you don't have access to the modal instance in the Visualforce page.
Fortunately we do have an alternative way which is the use of postMessage.

How does it work? 
First we need to the Visualforce page to send the message once the action is done. Which can be a click on button, a progress bar reaching 100%, an action function which has completed or many other scenarios. 

You just need to execute the following JavaScript code:
window.parent.postMessage('close', '*');

Now we need to capture this message from the JavaScript on the button and then close the modal. Here is how we do it. 
window.addEventListener('message', function(event){
  if (event.data === 'close'){
    box.hide();
  }
});

Below is the full implementation: 


Hope you like it. :)

Sunday, February 12, 2017

Introduction to Apex

Each year we are having struggle training fresh graduate from the University into learning the basic of Salesforce Apex programming language. They mixed up the syntax with what Java would look like.
So we came up with a list of things that would speed up the process of training.

Here's a list of the commonly used syntax in Apex and restrictions:

Hope this tutorial is useful to you.

Cheers!

# Intro to apex

## Basic operation
``` java
//variable declaration
Integer val = 0;
string str = 'Super test'; // apex allow only single quote for string variable
boolean isDeleted = true;

/*Concatenate string*/
string firstname = 'John';
string lastname = 'Doe';
string name = firstname + ' ' +  lastname;
```

## Debug Apex code
``` java
string name = 'Super test';
system.debug('### '+name); // ### Super test

```

## Collection
A collection in apex is either a "List", "Set" or a "Map"

``` java
/**
* List
*/
//Populating method 1
list<string> carList = new list<string>();  //initializing an empty list
/*Populating the list*/
carList.add('Honda');
carList.add('Toyota');
carList.add('Mazda');

//Populating method 2
list<string> carList = new list<string>{'BMW', 'Mercedes', 'Audi'};

/**
* Set
*/
set<string> referenceSet = new set<string>();
referenceSet.add('test');
//or
set<string> referenceSet = new set<string>{'test'};

/**
* Map
* A map consists of a key and value. The key should always be a primitive type (string, integer, id, ...).
*/
map<string, string> countryCodeMap = new map<string, string>(); //initiliazing an empty map
//Populating a map
countryCodeMap.put('Mauritius', 'MU');
countryCodeMap.put('France', 'FR');
//or
map<string, string> countryCodeMap = new map<string, string>{'Mauritius'=>'MU', 'France'=>'FR'};

//accessing a value for a specific key in the map
string franceCode = countryCodeMap.get('France'); //returns FR
```

## sObject
Any standard and custom object in Salesforce is represented as an sObject in Apex.

Example

| Object type | Name     | Api name (as represented in apex) |
| ----------- | ---------- | ----------------------------------- |
| Standard | Account  | Account |
| Standard | Contact | Contact |
| Custom | Car | Car__c |
| Custom | Job | Job__c |

``` java
//Create a new instance of an sObject
Contact con1 = new Contact(); //initializing an instance of a contact
con1.Firstname = 'Jane';
con1.Lastname = 'Doe';

// or
Contact con1 = new Contact(Firstname='Jane', Lastname='Doe');

/*custom object*/
Job__c job = new Job__c();

//creating an instance of an existing record
Account salesFr = new Account(Id='0012400000YwpHM'); //you just need to instantiate with the field "Id"

```

### Note
A lookup or master-detail relationship fields in apex is represented by an Id.

## DML
DML operations consists of:
- insert
- update
- upsert
- delete
- undelete
- merge

### Insert
```java
Account telecom = new Account(Name='Telecom');
insert telecom;
```
### Update
```java
telecom.Name = 'Telecom - Head office';
update telecom;
```
### Upsert
It does an insert if record not found else update if found.
Generally use with an ExternalId (a flag on a field to make it an index)
```java
//account does not exist
Account sbm = new Account(Name='SBM');
upsert sbm; // will create an account with Name = SBM
//account exist
Account sbm = new Account(Id='0012400000YwpHM', Name='SBM - Closed');
upsert sbm; // will update with Name = 'SBM - Closed'

//update a contact based on its external id (here Email is defined as external id)
Contact con1 = new Contact(Email='plop@test.com', Lastname='Plop');
upsert con1 Contact.Email;
```
### Delete and Undelete
Can only delete instance which contains an Id.
```java
Account sbm = new Account(Id='0012400000YwpHM');
delete sbm;

undelete sbm;
```

## SOQL queries
SOQL query will always return the following:
- an sobject
- a list of sobjects
- a list of objects

### Basic query
```java
//Returning only one record
Contact jane = [SELECT Id, Firstname, Lastname FROM Contact WHERE Id = '0032400000GRVvY'];

//returning a list of record
list<Account> accountList = [SELECT Id, Name FROM Account];
```
### Advanced query
```java
// returning a list of contact with their account name
list<Contact> contactList = [SELECT Id,
                                    Firstname,
                                    Lastname,
                                    Account.Name
                            FROM Contact
                            WHERE AccountId != null];

// returning list of account with their children(contacts)
list<Account> accountList = [SELECT Id, Name,
                                (SELECT Id, Firstname, Lastname from Contacts)
                            FROM Account];
```
Notice that the child relationship is in plural.
If a custom object was used here
- parent relationship: objectName**__r**
- child relationship: objectName**s__r**


## Loops
``` java
for(integer i = 0; i < size; i++){
  // code here
}

/*Example*/
list<string> firstnames = new list<string>{'John', 'Jane'};
list<string> lastnames = new list<string>{'Smith', 'Doe'};
list<string> names= new list<string>();
for(integer i = 0; i < firstnames.size(); i++){
  string name = firstnames[i] + ' ' + lastnames[i];
  names.add(name);
}

//or
for(type variable: list<type>){
  //do any operation with variable
}

/*Examples*/
integer total = 0;
list<Account> accountList = [SELECT id, NumberOfEmployees FROM Account];
for(Account acc: accountList){
  if (acc.NumberOfEmployees != null){
    total = total + acc.NumberOfEmployees;
  }
}

```

## Classes and Methods
``` java
public class Employee {
  public string name;
  public integer age;
  public datetime arrivedAt;
  public Employee(){
  }
  public void checkIn(){
    //void just do the action
    arrivedAt = System.now();
  }
  public boolean shouldRetire(){
    integer diff = 65 - age;
    if (diff <= 0){
      return true;
    }
    return false;
  }
  public static integer numEmployees(){
    list<Employee__c> employees = [select id from Employee__c];
    return employees.size();
  }
}

//Creating an instance of employee
Employee emp = new Employee();
emp.name = 'john';
emp.age = 30;
//call checkIn method for the employee
emp.checkIn(); // void method do the action only
retired = emp.shouldRetire(); // non void method should return a value

//Calling static methods
Employee.numEmployees();
```

Saturday, February 11, 2017

Nice css spinner for Visualforce pages

Did it ever happen that you have design a nice looking Visualforce page and had to insert a loading icon but didn't want to use the one provided by Salesforce (see image below)?

Well it happened to me a lot of time that I needed to find a reusable piece of code for a loading/spinner icon. Doing some research I found a that this guy, Tobias Ahlin, has come up with a SpinKit (https://github.com/tobiasahlin/SpinKit). So I decided to make a reusable component for having different kind of spinner with customize colors.

It is pretty easy to use, just need to copy the component on your Salesforce environment and execute some JavaScript whenever you want to toggle on and off the spinner/loading.

Source code can be found here: https://github.com/kevanmoothien/sfdc-spinner



The result should look something like that:

A live demo of all the spinners is available at: http://tobiasahlin.com/spinkit/

Hope you like this tutorial.

If you have any suggestions on how to improve this component, I will be glad to hear them.

Cheers!!

Installation

Click on the link below and add the codes in a visualforce component name "spinner" or any other name that sound best for you

Basic usage

Include the Visualforce component on the Visualforce page you want to use the spinner/loading like in the code below.
<apex:page>
  <c:spinner />
</apex:page>
Displaying the spinner
To display the spinner, a JavaScript code must be executed. Here are the code
km_spin(true); // to show the spinner
km_spin(false); // to hide the spinner

Advanced usage

Customizing the spinner
You can further customize the Spinner by adding some attributes such as in the code below:
<apex:page>
    <c:spinner spinner_name="wave"  spinner_color="red" />
</apex:page>
Possible value for "spinner_name" are:
  • rotating-plane
  • wave
  • wandering-cubes
  • spinner-pulse
  • double-bounce
  • chasing-dots
  • three-bounce
  • circle
  • cube-grid
  • fading-circle
  • folding-cube
Value for "spinner_color" is a hex or html color name


Thursday, February 9, 2017

Does a Lightning Component know if it is in a Community or a standard Lightning Salesforce page?



I have a component that implements both the interface for Community and Standard Lightning.
Some people suggest to add an attribute and set it in the Lightning App Builder or Community Builder so as to distinguish in which kind of environment we are.

It is quite annoying for the System Administrator to configure the behavior of the component each time it is needed.

But what if this can be achieved automatically by only a few lines of code?

Here is how I did it:

Your component must first extends a controller.

I Hope that this post will be helpful to you. Cheers!!
Lightning component .cmp aura:component implements="force:hasRecordId, force:appHostable, flexipage:availableForAllPageTypes, forceCommunity:availableForAllPageTypes" controller="CustomController"> aura:handler name="init" value="{!this}" action="{!c.init}"/> /aura:component Apex controller .cls public with sharing class CustomController { @AuraEnabled public static boolean isCommunity(){ Id siteId = Site.getSiteId(); if (siteId != null) { return true; } return false; } } Lightning component controller .js ({ init : function(component, event, helper) { var action = component.get("c.isCommunity"); action.setCallback(this, function(response) { var isCommunity = response.getReturnValue(); // do any operation needed here }); $A.enqueueAction(action); } })