Bootstrap

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.