jQuery

VanillaJs For Better Performance of Lightning Components

Posted on Updated on

Hi All,

Lightning is all about components. You can build applications by assembling components created by you and other developers. A component can contain other components, as well as HTML, CSS, JavaScript, or any other Web-enabled code.

If you have multiple Lightning Components on a Lightning Page/App with 3rd party libraries like jQuery,Bootstrap etc, you may face performance issues like slow loading, code conflicts, many others you don’t know.

Problems you may face while working with 3rd party libraries :

If you have 2 Lightning Components with different version of Libraries, they may conflict with each other.
If you are using same version, they may put unnecessary weight on Components which in turn load your component slowly.

So what could be the solution? The solution is to ensure that you really need to load 3rd party libraries or not.

Basically you should always avoid use of jQuery for very small things like getting element Id, Class, DOM manipulation and many others. To do these small things you have to import jQuery file in you component. Which will put unnecessary weight on your component.

Instead of this you can use getter setter methods provided by Framework or you can use VanillaJs.

You might be thinking what is “VanillaJs”?
Vanilla JavaScript is a fancy name developers have given to the core JavaScript and DOM API combined, and it is used to distinguish it from libraries such as jQuery.

VanillaJs is very easy to use, it is a fast, lightweight, cross-platform framework for building incredible, powerful JavaScript applications. You can read more about here.

VanillaJs is faster than jQuery see below comparison.

vanilla

I know you may have to write few more lines of code in comparison to jQuery, but it is better than putting unnecessary weight on components by importing library.

Comparison of jQuery and Vanilla JS for basic DOM manipulation.

Class selectors

// jQuery
$('.myClass');

// VanillaJs 
document.getElementsByClassName('myClass');

ID selectors

// jQuery
$('#myID');

// VanillaJs
document.getElementById('myID');

Tags

// jQuery
$('div');

// VanillaJs
document.getElementsByTagName('div');

Add and Remove Class

// jQuery
$('div').addClass('myClass');

// VanillaJs
var div = document.querySelector('div');
div.classList.add('myClass');

// jQuery
$('div').removeClass('myClass');

// VanillaJs
var div = document.querySelector('div');
div.classList.remove('myClass');

Add and Remove Attribute

// jQuery
$('.myClass').attr('disabled', true);

// VanillaJs
document.querySelector('.myClass').setAttribute('disabled', true);

// jQuery
$('.myClass').removeAttr('disabled');

// VanillaJs
document.querySelector('.myClass').removeAttribute('disabled');

Hope you will find VanillaJs better than jQuery with Lightning Components.

Thanks 🙂

DropBox Lightning Component

Posted on Updated on

Hi All,

Today i will be showing you DropBox Lightning Component created by me and my colleague Sushil Kumar.

Dropbox is a file hosting service operated by Dropbox, Inc., headquartered in San Francisco, California,
that offers cloud storage, file synchronization, personal cloud, and client software. There are limits in storage of files in Salesforce. If you need a secure and free storage space for your files, you can use DropBox Lightning Component to store files directly in your DropBox app from Salesforce.

Features of this Lightning Component are :

  1. You can use this component on any sObject.
  2. You can store files for a specific record.
  3. You can upload multiple files.
  4. You can delete files directly in DropBox.
  5. You can view you files.

Click here to install Manage Package in your org.

After installing package register for My Domain.

Make sure you have DropBox Account. If you don’t have you can sign up and create DropBox App as below.

Sign up Dropbox account from DropBox website.

After the Sign up login into your dropbox account and then create a Dropbox App using following steps:

  1. Go to on dropbox developer edition i.e. https://www.dropbox.com/developer
  2. Click on My Apps > Create App.
  3. Then fill all information about app and then click on create. See below screen shot.

dropbox

Manage Dropbox Key from Custom setting

Insert a record in custom setting using following steps:

  1. Navigate to Setup > Develop > Custom Settings, click on Manage of “Dropbox Key”.
  2. Click on New, than insert following value:

App Key : from DropBox App

App Secret : from DropBox App

Redirect URI : from salesforce <your domain>/apex/DropBoxOAuth or copy url from preview of DropBoxOAuth page.

isAuthentication : false

Click on Save.

Add Redirect URI in Dropbox App

To add Redirect URI, Open your Dropbox App and you must set auth2 Redirect URIs same as above Redirect URL.

That’s It.

Your final result will look like this.

Thanks. 🙂

Export Data in any format

Posted on Updated on

Hi All,

In this article i will be telling you how to export table data in any format like Excel, CSV, JSON, PDF, PNG.To implement this functionality I am using jQuery Library.

Credit : here.

pic

Plugin Features :

We can easily export any html tables to the following formats

  1. JSON
  2. XML
  3. PNG
  4. CSV
  5. TXT
  6. MS-Word
  7. Ms-Excel
  8. PDF

Script :

    $(document).ready(function(){
         $(".toggle").on("click",function(){
              var elm = $("#"+$(this).data("toggle"));
              if(elm.is(":visible"))
                  elm.addClass("hidden").removeClass("show");
              else
                  elm.addClass("show").removeClass("hidden");
              return false;
         });
    });

Button Panel :

<div class="pull-right">
	<button class="btn toggle" data-toggle="exportTable"><i class="fa fa-bars"></i> Export Data</button>
</div>
<div class="panel-body" id="exportTable" style="display:none">
	<div class="row">
		<div class="col-md-3">
			<div class="list-group border-bottom">
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'json',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/json.png')}" width="24"/> JSON</a>
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'json',escape:'false',ignoreColumn:'[2,3]'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/json.png')}" width="24"/> JSON (ignoreColumn)</a>
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'json',escape:'true'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/json.png')}" width="24"/> JSON (with Escape)</a>
			</div>
		</div>
		<div class="col-md-3">
			<div class="list-group border-bottom">
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'xml',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/xml.png')}" width="24"/> XML</a>
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'txt',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/txt.png')}" width="24"/> TXT</a>
			</div>
		</div>
		<div class="col-md-3">
			<div class="list-group border-bottom">
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'csv',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/csv.png')}" width="24"/> CSV</a>
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'excel',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/xls.png')}" width="24"/> XLS</a>
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'doc',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/word.png')}" width="24"/> Word</a>
			</div>
		</div>
		<div class="col-md-3">
			<div class="list-group border-bottom">
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'png',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/png.png')}" width="24"/> PNG</a>
				<a href="#" class="list-group-item" onClick ="$('#contacts').tableExport({type:'pdf',escape:'false'});"><img src="{!URLFOR($Resource.tableExporter,'tableExporter/images/pdf.png')}" width="24"/> PDF</a>
			</div>
		</div>
	</div>
</div>

Records Table :

<div class="panel panel-default">
	<div class="panel-heading">
		<h3 class="panel-title">Contact Details</h3>
	</div>
	<div class="panel-body panel-body-table">
		<table id="contacts" class="table table-striped">
			<thead>
				<tr>
					<th>FirstName</th>
					<th>LastName</th>
					<th>Email</th>
					<th>Phone</th>
				</tr>
			</thead>
			<tbody>
			<apex:repeat value="{!contacts}" var="con">
				<tr>
					<td>{!con.FirstName}</td>
					<td>{!con.LastName}</td>
					<td>{!con.Email}</td>
					<td>{!con.Phone}</td>
				</tr>
			</apex:repeat>
			</tbody>
		</table>
	</div>
</div>

So That’s It.

Share Content on WhatsApp Using Lightning

Posted on Updated on

Hi All,

Whats-app is one of the most popular messaging apps in the world.One third of world’s population is using Whats-app on their smartphones.That is why I thought to implement a functionality by which user can share content on Whats-app. I implemented this with Salesforce1 Lightning.

I got this idea from here.
If you need complete code you can send me an email on balkishan.kachawa@gmail.com

In this demo I am showing you user’s feeds with WhatsApp Share button. When you click on this button it will ask you to share your specific feed with any contact in your mobile device. When complete it will look like this:
IMG-20150702-WA0002

Here is the complete code let’s walk through it :

FeedItemController.apxc
public class FeedItemController{
    @AuraEnabled
    public static List&lt;FeedItem&gt; getFeedItems(){
        return [SELECT Body FROM FeedItem WHERE InsertedById =: UserInfo.getUserId() ORDER BY CreatedDate DESC LIMIT 10 ];
    }
}

In this controller I have created a method getFeedItems() to return feeds of current logged in user.

WhatsAppLightningComponent.cmp
<aura:component controller="bklightning.FeedItemController" implements="force:appHostable">
	
    <ltng:require styles="/resource/whatsappfiles/whatsappfiles/bootstrap,
				/resource/whatsappfiles/whatsappfiles/whatsappbutton.css"
                  scripts="/resource/whatsappfiles/whatsappfiles/jquerymin.js" 
                  afterScriptsLoaded="{!c.afterLoaded}"></ltng:require>
    
    <aura:attribute name="feeds" type="FeedItem[]" />
    
    <div class="page-header page-header-anchor">
    	<h1>Share Your Feeds</h1>
    </div>
    <div id="msg" style="display:none;color:red">
    	Please share this article in mobile device
    </div>   
    <aura:iteration items="{!v.feeds}" var="feed">
        <div class="card">
          	<div class="card-heading">
            	{!feed.Body}
          	</div>
          	<div class="card-detail">
            	<a data-text="{!feed.Body}" class="whatsapp w3_whatsapp_btn w3_whatsapp_btn_large">Share</a>
        	</div>
        </div>
    </aura:iteration>
</aura:component>

Resources for this Lightning Component could be found here jQuery , Bootstrap.

WhatsAppLightningComponentHelper.js
({
	loadFeeds : function(component) {
		var action = component.get("c.getFeedItems");
        action.setCallback(this, function(a) {
            component.set("v.feeds", a.getReturnValue());
        });
        $A.enqueueAction(action);
	},
    
    whatsAppJS : function(component){
        var isMobile = {
            Android: function() {
                return navigator.userAgent.match(/Android/i);
            },
            BlackBerry: function() {
                return navigator.userAgent.match(/BlackBerry/i);
            },
            iOS: function() {
                return navigator.userAgent.match(/iPhone|iPad|iPod/i);
            },
            Opera: function() {
                return navigator.userAgent.match(/Opera Mini/i);
            },
            Windows: function() {
                return navigator.userAgent.match(/IEMobile/i);
            },
            any: function() {
                return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows());
            }
        };
    	
        jQuery('.whatsapp').click(function(){
            if( isMobile.any() ) {
 				var text = jQuery(this).attr("data-text");
                var message = encodeURIComponent(text);
                var whatsapp_url = "whatsapp://send?text=" + message;
                window.location.href = whatsapp_url;
            } else {
                jQuery('#msg').show();
            }
        })
    }
})

In WhatsAppLightningComponentHelper.js whatsAppJs() method is used to share content on Your WhatsApp.It can support any mobile device but we know that Lightning app is not supporting Android and other devices so it will not work for them.
I did not change code because I hope Lightning will support other Mobile Devices in future.

Please change Namespace to your Namespace before running this code.

Thanks 🙂

Lightning Wizard Component with jQuery and Bootstrap

Posted on Updated on

Hi All,

In this post I am sharing with you a Lightning Wizard Component built with Bootstrap and jQuery.
It is a multi step form wizard with Progress Bar and jQuery Validations.

IMG-20150623-WA0002 IMG-20150623-WA0005 IMG-20150623-WA0004

Requirements :
1) Download latest version of Bootstrap and jQuery.
2) “bklightning” namespace to “YourNamespace”.

Here is full code :

WizardDemoComponent.cmp
<aura:component controller="bklightning.CreateContactController" implements="force:appHostable">
    <ltng:require styles="/resource/wizarddemo/wizarddemo/bootstrap.min.css,/resource/wizarddemo/wizarddemo/style.css"
                  scripts="/resource/wizarddemo/wizarddemo/jquery.min.js,
                           /resource/wizarddemo/wizarddemo/jquery-ui.min.js,
                           /resource/wizarddemo/wizarddemo/jquery.validate.js,
                           /resource/wizarddemo/wizarddemo/bootstrap.min.js"
                  afterScriptsLoaded="{!c.afterLoaded}"/>
    
    <aura:attribute name="newContact" type="bklightning__ContactDetail__c"
                                        default="{ 'sobjectType': 'bklightning__ContactDetail__c'}"/>
    
    <div class="container">
    <br/><br/>
	<form class="form-horizontal form" id="form">
		<div class="col-md-8 col-md-offset-2">   	
			<div class="progress">
			  <div class="progress-bar progress-bar-success progress-bar-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100"></div>
			</div>
		
			<div class="box row-fluid">	
				<br/>
				<div class="step">
					<div class="form-group">
						<label for="fname" class="col-sm-2 control-label">First Name</label>
						<div class="col-sm-10">
						  <input type="text" name="fname" value="{!v.newContact.bklightning__Firstname__c}" class="form-control" id="fname" placeholder="First Name"/>
						</div>
					</div>
					<div class="form-group">
						<label for="lname" class="col-sm-2 control-label">Last Name</label>
						<div class="col-sm-10">
						  <input type="text" name="lname" value="{!v.newContact.bklightning__Lastname__c}"  class="form-control" id="lname" placeholder="Last Name"/>
						</div>
					</div>
					<div class="form-group">
						<label for="email" class="col-sm-2 control-label">Email</label>
						<div class="col-sm-10">
						  <input type="text" name="email" value="{!v.newContact.bklightning__Email__c}" class="form-control" id="email" placeholder="email"/>
						</div>
					</div>			  
					  
				</div>
				<div class="step">
					<div class="form-group">
						<label for="phone" class="col-sm-2 control-label">Phone</label>
						<div class="col-sm-10">
						  <input type="text" name="phone" value="{!v.newContact.bklightning__Phone__c}" class="form-control" id="phone" placeholder="Phone"/>
						</div>
					</div>
					<div class="form-group">
						<label for="address" class="col-sm-2 control-label">Address</label>
						<div class="col-sm-10">
						  <textarea name="address" class="form-control" id="address" cols="10" rows="5" >{!v.newContact.bklightning__Address__c}</textarea>
						</div>
					</div>			  
					  
				</div>
				<div class="step display">
					<div class="form-group">
						<label for="company" class="col-sm-2 control-label">Company</label>
						<div class="col-sm-10">
							<input type="text" name="company" value="{!v.newContact.bklightning__Company__c}" class="form-control" id="company" placeholder="Company"/>
						</div>
					</div>
					<div class="form-group">
						<label for="numberofemp" class="col-sm-2 control-label">Number of Employees</label>
						<div class="col-sm-10">
							<input type="text" name="numberofemp" value="{!v.newContact.bklightning__NumberOfEmployee__c}" class="form-control" id="numberofemp" placeholder="Number of Employees"/>
						</div>
					</div>			  
					<div class="form-group">
						<label for="website" class="col-sm-2 control-label">Website</label>
						<div class="col-sm-10">
							<input type="text" name="website" value="{!v.newContact.bklightning__Website__c}" class="form-control" id="website" placeholder="Website"/>
						</div>
					</div>			  
				</div>
			
				<div class="row">
					<div class="showMsg" style="display:none;color:red;text-align:center;">
						<b>Your Information Saved Successfully</b><br/>
					</div>
				</div>
            
				<div class="row">
					<div class="col-sm-12">
						<div class="pull-right">
							<button type="button" class="action btn-sky text-capitalize back btn">Back</button>
							<button type="button" class="action btn-sky text-capitalize next btn">Next</button>
							<button type="button" onclick="{!c.saveContact}" class="action btn-hot text-capitalize submit btn">Submit</button>
						</div>
					</div>
				</div>			

			</div>
		
			</div> 
		</form> 
	</div>
</aura:component>

In WizardDemoComponent.cmp you can see I have used Latest Bootstrap and jQuery Library.
When all scripts loaded I am calling afterLoaded() function of WizardDemoComponentController.js.

WizardDemoComponentController.js
({
	afterLoaded : function(component, event, helper) {
        var current = 1;
        
        widget = jQuery(".step");
		btnnext = jQuery(".next");
		btnback = jQuery(".back"); 
		btnsubmit = jQuery(".submit");
        
        widget.not(':eq(0)').hide();
		
		helper.hideButtons(component,widget,current);
        helper.setProgress(component,widget,current);
        
        //Next Button Action
        btnnext.click(function(){
			if(current < widget.length){
				// Check validation
				if(jQuery(".form").valid()){
					widget.show();
					widget.not(':eq('+(current++)+')').hide();
					helper.setProgress(component,widget,current);
				}
			}
			helper.hideButtons(component,widget,current);
		})
        
        //Back Button Action
        btnback.click(function(){
			if(current > 1){
				current = current - 2;
				if(current < widget.length){
					widget.show();
					widget.not(':eq('+(current++)+')').hide();
					helper.setProgress(component,widget,current);
				}
			}
			helper.hideButtons(component,widget,current);
		})
		
		jQuery('.form').validate({ // initialize plugin
			ignore:":not(:visible)",			
			rules: {
				fname     : "required",
				lname     : "required",
				email    : {required : true, email:true},
				phone  : {required : true, number:true},
				address : "required",
				company : "required",
				website : {required : true, url:true},
				numberofemp : {required : true, number:true},
			},
	    });
        
	},
    
    saveContact : function(component, event, helper) {
        component.set("v.newContact.bklightning__Firstname__c",jQuery("#fname").val());
        component.set("v.newContact.bklightning__Lastname__c",jQuery("#lname").val());
        component.set("v.newContact.bklightning__Email__c",jQuery("#email").val());
        component.set("v.newContact.bklightning__Phone__c",jQuery("#phone").val());
        component.set("v.newContact.bklightning__Address__c",jQuery("textarea#address").val());
        component.set("v.newContact.bklightning__Company__c",jQuery("#company").val());
        component.set("v.newContact.bklightning__NumberOfEmployee__c",jQuery("#numberofemp").val());
        component.set("v.newContact.bklightning__Website__c",jQuery("#website").val());
        
        var newContact = component.get("v.newContact");
        
		helper.upsertContact(component, newContact); 	
        
        jQuery('.showMsg').show();
        jQuery('.form')[0].reset();
    }
    
})

In afterLoaded method of WizardDemoComponentController.js I am defining validations and click events.

WizardDemoComponentHelper.js
({
	setProgress : function(component,widget,currstep) {
		var percent = parseFloat(100 / widget.length) * currstep;
		percent = percent.toFixed();
		jQuery(".progress-bar").css("width",percent+"%").html(percent+"%");
	},
    
    hideButtons : function(component, widget,current) {
		var limit = parseInt(widget.length); 

		jQuery(".action").hide();

		if(current < limit) jQuery(".next").show();
		if(current > 1) jQuery(".back").show();
		if (current == limit) { 
			// Show entered values
			jQuery(".display label:not(.control-label)").each(function(){
				console.log(jQuery(this).find("label:not(.control-label)").html(jQuery("#"+jQuery(this).data("id")).val()));	
			});
			jQuery(".next").hide(); 
			jQuery(".submit").show();
		}	
	},
    
    upsertContact : function(component, newContact) {
        var action = component.get("c.createContact");
        action.setParams({
          "con": newContact
        });
        action.setCallback(this, function(a) {
        });
        $A.enqueueAction(action);
    }
})

In WizardDemoComponentHelper.js setProgress() and hideButtons() methods are used to set progress-bar and to hide buttons as wizard progresses.

So that’s it,Simple.