CSV File Download from Lightning Component

Use below code to download data as a  CSV file from the lightning component.

Component 

<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global">
    <!-- 1.attribute to store return value and show on component. -->
    <aura:attribute name="gridData" type="Object"/>
    <!-- 2.handler to call method "doInit" of jsCOntroller on loading of component. -->
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> 
    <div class="slds-m-around--xx-large">     
        <button class="slds-button slds-button--brand" onclick="{!c.downloadCSV}">Download As CSV</button> <br/><br/>
        <table class="slds-table slds-table--bordered" id="pbId">
            <!-- 3.Header of table. -->
            <thead>
                <tr class="slds-text-heading--label">            	
                    <aura:iteration items="{!v.gridData.headers}" var="col">                             
                        <th class="{!col.cssClass}"> {!col.title} </th>
                    </aura:iteration>             
                </tr>        	
            </thead>
            <!-- 4.Body of table. -->
            <tbody>
                <!-- Limitation - we cannot use indexvar of iterator control to refer header json information else, instead of defining css class for each column, we could have used it from header only -->
                <aura:iteration items="{!v.gridData.rows}" var="row">
                    <tr class="slds-hint-parent">
                        <aura:iteration items="{!row.vals}" var="col" indexVar="idx">                       
                            <td id="{!'theTd__' + idx}" class="{!col.cssClass}">{!col.val}</td>
                        </aura:iteration>
                    </tr>
                </aura:iteration>           
            </tbody>   
        </table>
    </div>
</aura:component>

Controller.js

({
    doInit : function(component, event, helper) {
        // 1. Calling helper method "doInit".
        helper.doInit(component, event, helper);
    },
    // 2. Method to download CSV file.
    downloadCSV : function(component, event, helper,fileTitle) {
        // 3. Getting table data to download it in CSV.
        var gridData = component.get("v.gridData");
        // 4. Spliting headers form table.
        var gridDataHeaders = gridData["headers"];
        // 5. Spliting row form table.
        var gridDataRows = gridData["rows"];
        // 6. CSV download.
        var csv = '';
        for(var i = 0; i < gridDataHeaders.length; i++){         
            csv += (i === (gridDataHeaders.length - 1)) ? gridDataHeaders[i]["title"] : gridDataHeaders[i]["title"] + ','; 
        }
        csv += "\n";
        var data = [];
        for(var i = 0; i < gridDataRows.length; i++){
            var gridRowIns = gridDataRows[i];
            var gridRowInsVals = gridRowIns["vals"];
            var tempRow = [];
            for(var j = 0; j < gridRowInsVals.length; j++){                                     
                var tempValue = gridRowInsVals[j]["val"];
                if(tempValue.includes(',')){
                    tempValue = "\"" + tempValue + "\"";
                }
                tempValue = tempValue.replace(/(\r\n|\n|\r)/gm,"");                 
                tempRow.push(tempValue);
            }
            data.push(tempRow); 
        }
        data.forEach(function(row){
            csv += row.join(',');
            csv += "\n";
        });
        // 6. To download table in CSV format.
        var hiddenElement = document.createElement('a');
        hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
        hiddenElement.target = '_blank';
        hiddenElement.download = 'fileTitle'+'.csv'; 
        hiddenElement.click();
    }
    
})

helper.js

({
    
    doInit : function(component, event, helper) {
        // 1. Calling method "getSampleJSON()" and parsing it into JSON object.
        var jsonData = JSON.parse(helper.getSampleJSON());
        // 2. Setting parsed data in attribute "gridData".
        component.set("v.gridData",jsonData);
    },
    getSampleJSON : function(){
        // 3. Variable declaration and assigning value to show in component.
        var jsonStr = '{"rows":[{"vals":[{"val":"Salesforce","cssClass":""},{"val":"SFO","cssClass":""},{"val":"info@Salesforce.com","cssClass":""},{"val":"8602229632","cssClass":"responsiveHide"}]},{"vals":[{"val":"Microsoft","cssClass":""},{"val":"SFO","cssClass":""},{"val":"info@microsoft.com","cssClass":""},{"val":"8602283222","cssClass":"responsiveHide"}]},{"vals":[{"val":"SAP","cssClass":""},{"val":"SFO","cssClass":""},{"val":"info@SAP.com","cssClass":""},{"val":"8600942222","cssClass":"responsiveHide"}]},{"vals":[{"val":"Google","cssClass":""},{"val":"SFO","cssClass":""},{"val":"info@Google.com","cssClass":""},{"val":"8602479222","cssClass":"responsiveHide"}]}],"headers":[{"title":"ClientName","isSortable":false,"dataType":"","cssClass":""},{"title":"Address","isSortable":false,"dataType":"","cssClass":""},{"title":"Email","isSortable":false,"dataType":"","cssClass":""},{"title":"Mobile","isSortable":false,"dataType":"","cssClass":"responsiveHide"}]}';
        return jsonStr;
    }           
})

Sample App for testing

<aura:application extends="force:slds">
    <c:DownloadAsCsv/>
</aura:application>

Lightning Components winter 19 Highlights

In this post, I am going to quickly recall on the winter 19 Salesforce lightning component changes and improvements.

1.Org Setting for Stricter Content Security Policy 

Winter 19 changed the critical update to an org setting to give you greater control over its enablement. This setting enables Stricter Content Security Policy (CSP), which prohibits the use of unsafe-inline for script-src to mitigate the risk of cross-site scripting attacks. In the previous release, stricter CSP was controlled by the “Enable Stricter Content Security Policy for Lightning Components” critical update. To enable stricter CSP:
1. From Setup, enter Session in the Quick Find box, and then select Session Settings.
2. Deselect Enable Stricter Content Security Policy.
3. Click Save.

2.Freeze JavaScript Prototypes for Improved Security and Stability

In JavaScript, each object has a prototype object. An object inherits methods and properties from its prototype object. Prototypes are shared between all objects of the same type. If a component author modifies a JavaScript prototype of a shared object, it can introduce unexpected behavior and potential security issues. Freezing JavaScript prototypes prevents Lightning component authors from modifying
JavaScript prototypes of global objects that are shared between namespaces. This restriction enables better code separation between components and prevents malicious or inadvertent tampering of shared objects, such as the JavaScript APIs or DOM APIs. To freeze JavaScript prototypes, from Setup, enter Session in the
Quick Find box, and then select Session Settings. Select Freeze JavaScript Prototypes and click Save

before enabling you can see entire prototype objects and methods in the console as shown below.

after enable, you can able to see all the prototype methods are disabled.

3: Enable CDN to Load Lightning Experience Faster

Load Lightning Experience and other apps faster by enabling Akamai’s content delivery network (CDN) to serve the static content for Lightning Component framework. A CDN generally speeds up page load time, but it also changes the source domain that serves the files. If your company has IP range restrictions for content served from Salesforce, test thoroughly before enabling this setting.To enable CDN, from Setup, enter Session in the Quick Find box, and then select Session Settings. Select Enable Content Delivery Network (CDN) for Lightning Component framework, and click Save.

this is not like normal open source CDN 

4. lightning:empApi

Embed the lightning:empApi component in your custom Lightning component to subscribe to a streaming event channel and receive event notifications. You can subscribe to any type of event channel on the Lightning Platform, including channels for platform events, PushTopic, and generic events, and Change Data Capture (Developer Preview) events. The lightning:empApi the component uses a shared CometD-based Streaming API connection, enabling you to run multiple streaming apps in the browser.

5. lightning:map

The lightning:map component securely displays a map of one or more locations using Google Maps. You can pass markers to the component to define the locations to map. A marker can be a coordinate pair of latitude and longitude, or a set of address elements: City, Country, PostalCode, State, and Street. Here’s the map component with one address. When you specify multiple locations, the map component creates clickable tiles for each location. You can specify a title to display
above the list of addresses. You can also show a footer with an “Open in Google Maps” link and specify an initial zoom level for the map.

6. lightning:menuDivider

This component is used as a child component of lightning:buttonMenu. Use lightning:menuDivider to create a dividing line after a menu item. By default, space is added above and below the divider. Use variant=”compact” with
lightning:menuDivider to reduce the space.

7. lightning:menuSubheader

This component is used as a child component of lightning:buttonMenu. Use lightning:menuSubheader to create subheadings in the list of menu items. Specify the text of the heading using the label attribute.

8. lightning:accordion Multi Select Options 

Now with this new allowMultipleSectionsOpen attribute, you can able to open multiple sections of the accordion at the same time. By default, only one accordion section is expanded at a time and onsectiontoggle Specifies a handler for the event that’s fired when the open sections change. The event passes an
array of all open sections in the accordion.

9. lightning:formattedRichText disable HTML links 

With the new disableLinkify attribute now you able to disable the links on formattedRichText. this attribute prevents the component from creating links automatically for linkable text in the formatted output

            <lightning:formattedRichText disableLinkify="true" value="This is a link to &lt;a href=&quot;http://www.salesforce.com&quot;&gt;Salesforce&lt;/a&gt;"></lightning:formattedRichText>

10. lightning:inputField geolocation support 

The lightning:inputField component now supports the geolocation field type. It displays input fields for entering latitude and longitude in decimal degrees.

 

Visualforce Winter 19 Highlights

This is quick highlights of winter 19 visualforce improvements.

1.New Visualforce Access Metrics Fields

Use the new ProfileId and LogDate access metrics fields to prioritize which Visualforce pages to migrate to Lightning Experience. To decide which Visualforce pages to migrate to Lightning Experience, it’s helpful to know which pages are used most often and by whom. These new Visualforce Access Metrics fields show you that information. The ProfileId field shows the Salesforce profile ID of the user who viewed the Visualforce page. The LogDate field shows the
date that the user accessed the page. This field provides more insight into page usage than the MetricsDate field, which represents the date the metrics are collected. To query metrics on the Visualforce pages in your org, use the VisualforceAccessMetrics object and include the ProfileId and
LogDate fields.

Select Id ,ProfileId, MetricsDate ,LogDate from VisualforceAccessMetrics

2. Securely Retrieve and Display Third-Party Images 

Protect your users from unauthorized requests by using the IMAGEPROXYURL function to securely fetch images outside your org’s server. Loading a third-party image can initiate a malicious authentication request meant to steal Salesforce usernames and passwords. This Visualforce function loads external images over HTTPS and prevents images from requesting user credentials. To securely retrieve an external image, include the IMAGEPROXYURL function on the src attribute of a tag or the value attribute of an object.

<img src={!IMAGEPROXYURL("http://exampledomain.com/pic.png")}/>
<apex:image value="{!IMAGEPROXYURL("http://exampledomain.com/pic.png")}"/>

3.URL Redirect Parameters Are No Longer Case-Sensitive

The protected URL parameters used in Visualforce pages—retURL, startURL, cancelURL, and saveURL—are no longer case-sensitive. If you change the parameter value from retURL to returl, the system now recognizes it as a protected parameter. Protected URL parameters allow redirects from Visualforce pages to salesforce.com or *.force.com domains and prevent malicious
redirects to third-party domains.

4.Improve Security by Isolating Untrusted Third-Party Content with iframes

You can now isolate HTML static resources on a separate domain using iframes. Using a separate domain to embed information from untrusted sources protects your Visualforce content.To reference a static HTML file on a separate domain, use $IFrameResource.<resource_name> as a merge field, where resource_name is the name you specified when you uploaded the static resource

 

Apex Winter 19 Highlights

In this post, I am going to quick recall on the winter 19 Salesforce lightning component changes and improvements.

1.Mark Apex Methods as Cacheable

Prior to Winter ’19, to cache data returned from an Apex method, you had to call setStorable() in JavaScript code on every action that called the Apex method. Now you can mark the Apex method as storable (cacheable) and get rid of any setStorable() calls in JavaScript code.

Mark an Apex method as storable (cacheable) instead of using setStorable() on every JavaScript action that calls the Apex method to centralize your caching notation for a method in the Apex class. Marking a method as storable improves your component’s performance by quickly showing cached data from client-side storage without waiting for a server trip. If the cached data is stale, the framework retrieves the latest data from the server. Caching is especially beneficial for users on high-latency, slow, or unreliable connections, such as 3G networks. To cache data returned from an Apex method for any component with an API version of 44.0 or later, annotate the Apex method with
@AuraEnabled(cacheable=true). For example:

@AuraEnabled(cacheable=true)
public static Account getAccount(Id accountId) {
// your code here
}

2. Fire Platform Events from Batch Apex Classes (Beta)

Batch Apex classes can now opt in to fire platform events when encountering an error or exception. Event records provide more granular tracking of errors than the Apex Jobs UI because they include the record IDs being processed, exception type, exception message, and stack trace. You can also incorporate custom handling and retry logic for failures. Clients listening on an event can tell how often it failed, which records were in scope at the time of failure, and other exception details. Events are also fired for Salesforce Platform internal errors and other “uncatchable” Apex exceptions like LimitExceptions that are caused by reaching governor limits.

global with sharing class PlatformEventRaise implements Database.Batchable<SObject>, Database.RaisesPlatformEvents{
    // class implementation
    global Database.QueryLocator start(Database.BatchableContext BC){
        return Database.getQueryLocator('Select Id ,Name,Rating,Industry, BillingAddress,BillingStreet,BillingCity, BillingCountry, BillingPostalCode,BillingState,Phone from Account  where BillingStreet!=NULL');
    }
    
    global void execute(Database.BatchableContext BC, List<sObject> scope){
        
        List<Account> accs =(List<Account>) scope ; 
        List<Cloud_News__e> cnewList = new List<Cloud_News__e>();
        for(Account a : accs){
            // Create an instance of the event and store it in the newsEvent variable
            Cloud_News__e newsEvent = new Cloud_News__e(
                Location__c=a.BillingStreet, 
                Urgent__c=true, 
                News_Content__c=a.BillingStreet);
            cnewList.add(newsEvent) ;
            
        }
        EventBus.publish(cnewList);
        
    }
    
    global void finish(Database.BatchableContext BC){
    }
}

3. Use Inherited Sharing to Secure Your Apex Code

You can now specify the inherited sharing keyword on an Apex class, which allows the class to run in the sharing mode of the class that called it. Using inherited sharing enables you to pass security review and ensure that your privileged Apex code is not used in unexpected or insecure ways. An Apex class with inherited sharing runs as with sharing when used as a Visualforce page controller, Apex REST service, or an entry point to an Apex transaction. This example declares an Apex class with inherited sharing and a Visualforce invocation of that Apex code. Because of the inherited sharing declaration, only contacts for which the running user has sharing access are displayed.

If the declaration is omitted, even contacts that the user has no rights to view are displayed due to the insecure default behavior of omitting the declaration.

public inherited sharing class InheritedSharingClass{
public List<Contact> getAllTheSecrets(){
return [SELECT Name FROM Contact];
}
}
<apex:page controller="InheritedSharingClass">
<apex:repeat value="{!allTheSecrets}" var="record">
{!record.Name}
</apex:repeat>
</apex:page>

 

4. Get Domain URL from Apex

Use the new System.Url.getOrgDomainUrl() method to interact with Salesforce REST and SOAP APIs in Apex code. Use getOrgDomainUrl() in orgs with or without My Domain to retrieve canonical URLs. For example, https://yourDomain.my.salesforce.com, or, for orgs without My Domain enabled https://yourInstance.salesforce.com&nbsp;.

Url.getOrgDomainUrl().toExternalForm()

5. Get Session Id in Asynchronous Context  

UserInfo.getSessionId() method to retrieve session IDs, even when your code runs asynchronously.  Previously, orgs with My Domain enabled could access some API features from Apex code only after setting up remote site settings or named credentials. Some objects, such as DatedExchangeRate, are accessible only through the API. You can use getSessionId() both synchronously and asynchronously.  In asynchronous Apex (Batch, Future, Queueable, or Scheduled Apex), this method returns the session ID only when the code is run by an active, valid user. When the code is run by an internal user, such as the automated process user or a proxy user, the method returns null.

Http h = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint(Url.getOrgDomainUrl().toExternalForm()
+ '/services/data/v44.0/limits');
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
HttpResponse res = h.send(req);

6.Share Extensible Functionality with the Callable Interface

The System.Callable interface enables you to use a common interface to build loosely coupled integrations between Apex classes or triggers, even for code in separate packages. Agreeing upon a common interface enables developers from different companies or different departments to build upon one another’s solutions. Implement this interface to enable the broader community, which might have different solutions than the ones you had in mind, to extend your code’s functionality.

public class Extension implements Callable {

   // Actual method
   String concatStrings(String stringValue) {
     return stringValue + stringValue;
   }

   // Actual method
   Decimal multiplyNumbers(Decimal decimalValue) {
     return decimalValue * decimalValue;
   }

   // Dispatch actual methods
   public Object call(String action, Map<String, Object> args) {
     switch on action {
       when 'concatStrings' {
         return this.concatStrings((String)args.get('stringValue'));
       }
       when 'multiplyNumbers' {
         return this.multiplyNumbers((Decimal)args.get('decimalValue'));
       }
       when else {
        throw new ExtensionMalformedCallException('Method not implemented');
       }
     }
   }

   public class ExtensionMalformedCallException extends Exception {}
}

 

7.Instantiate Custom Metadata Types in Apex

Now you can able to Instantiate Custom Metadata Types in Apex direly. You can now edit custom metadata records in memory within Apex. Previously, custom metadata records queried with SOQL in Apex were immutable. Audit fields (CreatedDate, CreatedBy, LastModifiedDate, LastModifiedBy, SystemModStamp) and calculated fields remain uneditable. DML operations aren’t allowed on custom metadata in Apex or the Partner or Enterprise APIs. DML operations can be done with the Apex Metadata API.

In this example, the first method is instantiating a custom metadata record, but no records are inserted into memory. The second the method retrieves a record, changes it, and returns it to the caller, but the change is not updated in the database.

public class CustomMetadataService{
    public CustomMetadataService() {}
    /**
* This method instantiates a custom metadata record of type Country_Code__mdt 
* and sets the DeveloperName to the input String.
* Note that the record is not inserted into the database,
* and would not be found by a SOQL query.
*/
    public Country_Code__mdt getCustomMetadataRecord(String myName) {
        Country_Code__mdt theRecord = new Country_Code__mdt();
        theRecord.DeveloperName = myName;
        return theRecord;
    }
    /**
* This method retrieves a custom metadata record, changes a field, and returns it
* to the caller. Note that the changed record is not updated in the database.
*/
    public Country_Code__mdt getChangedCustomMetadataRecord(String myNewName) {
        Country_Code__mdt theRecord = [SELECT Id, DeveloperName from
                                       Country_Code__mdt LIMIT 1];
        theRecord.DeveloperName = myNewName;
        return theRecord;
    }
    
    /**
* This method retrieves a custom metadata record,if the metadata found return the values from database 
* Other wise instantiates a custom metadata record and return it 
*/
    public Country_Code__mdt getChangedCustomMetadata(String myNewName) {
        Country_Code__mdt theRecord ; 
        theRecord = [SELECT Id, DeveloperName from
                     Country_Code__mdt LIMIT 1];
        if(theRecord.DeveloperName!=null){
            return theRecord;
        }else{
            theRecord = new Country_Code__mdt();
            theRecord.DeveloperName = 'United_States';
            return theRecord;  
        }
    }
    
}

 

8.Prediction Field type

isAiPredictionField() from Schema.DescribeFieldResult Returns a Boolean indicating whether the field is enabled to display Einstein prediction data.d

9.Scale Your Event-Based Apps with High-Volume Platform Events (Pilot)

Use high-volume platform events to publish and process millions of events efficiently. This pilot was offered in the last release, and salesforce made enhancements for this release. Choose the platform event type that suits your business needs. For applications that receive several million events per day, use high-volume platform events through the pilot program. For applications that receive up to a million events per day, use standard-volume platform events.Y ou can define a high-volume platform event from the user interface or through Metadata API. From the UI, in Setup, enter Platform Events in the Quick Find box, then select Platform Events. When completing the standard fields, select High Volume for Event Type.In Metadata API, the event definition is represented in the CustomObject type with eventType set to HighVolume.Publish and subscribe to high-volume platform events in the same way that you publish and subscribe to standard-volume platform events. You can use declarative tools, such as Process Builder and flow, or write code with Apex and CometD API apps.
High-volume platform events are published asynchronously so that the system can process high loads of events efficiently. The publishing call places the publish request in a queue. The event message might not be published immediately after the call returns, but it is published when system resources are available. High-volume events are stored for up to three days, and stored events can be replayed.