Wednesday, December 31, 2014

Accessing / Controlling Form fields in Visualforce pages using Jquery

It's a most common requirement that we need to access Form fields using JavaScript in any web technologies, for different reasons. In Salesforce too we can access / control using JavaScript. Lets understand how to accomplish this using below example.

Problem Statement: We have an object named Locations in Salesforce in which we store location details, that includes Address, City, Province / State , Country, Geo Co-ordinates etc. So, in a new or edit screen of a record, we want to provide a map where user can pick the location and it should automatically fill all the available details into the fields and on top of it, user can modify if any changes needed, then Save the record.

Solution: One among the easiest ways to provide a solution for above problem is having a map in the Form screen using JQuery Maps API and upon location changed in the map, updating the details of location ( fetched using API ) into the existing fields using JavaScript by accessing  through DOM.

To do this, we need to create a Visualforce page as we can't directly add custom code into default form screens in Salesforce. You can follow below steps to accomplish it

  1. Login to Salesforce
  2. Under Logged in User name drop down, select 'Setup'
  3. In left navigation, under 'App Setup' section go to 'Develop' and then 'Pages'
  4. List of all Visaulforce Pages are displayed. Now click on New button
  5. Fill in all the basic details of the new Page
  6. In the Visualforce Markup section, add below code and save it.
 <apex:page id="LocationPage" standardcontroller="Location__c" tabstyle="Location__c">  
      <apex:form id="FormLocation" >  
           <apex:sectionheader title="Information" subtitle="{!if(Location__c.Id==null,'New Location',Location__c.Name)}"></apex:sectionheader>  
           <apex:pageblock mode="edit" id="locationPB" title="Location Edit">  
                <apex:pageblockbuttons >  
                     <apex:commandbutton action="{!save}" value="Save"></apex:commandbutton>  
                     <apex:commandbutton action="{!cancel}" value="Cancel"></apex:commandbutton>  
                </apex:pageblockbuttons>  
                <apex:pagemessages ></apex:pagemessages> <!-- displays all message generated by the component -->  
                <apex:pageblocksection id="AddressInformationPBS" title="Address Information">  
                     <apex:inputfield value="{!Location__c.Address__c}" id="Address" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.Zone__c}" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.City__c}" id="City" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.Geo_Location__Latitude__s}" id="Latitude" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.Province__c}" id="Province" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.Geo_Location__Longitude__s}" id="Longitude" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.Country_Code__c}" id="Country" ></apex:inputfield>  
                     <apex:inputfield value="{!Location__c.Zip_Code__c}" id="Zip" ></apex:inputfield>  
                </apex:pageblocksection>  
                <apex:pageblocksection id="AddressPickerPBS" title="Pick Address using Map">  
                     <div id='map' style='width:100%;height:200px;'></div>  
                     <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>  
                     <script type="text/javascript" src='https://maps.google.com/maps/api/js?sensor=false&libraries=places'></script>  
                     <script src="https://rawgit.com/Logicify/jquery-locationpicker-plugin/master/locationpicker.jquery.js"></script>  
                     <script>  
                          $('#map').locationpicker({  
                               location: {    
                                    latitude: {!if(Location__c.Geo_Location__Latitude__s==null,17.4512887508432,Location__c.Geo_Location__Latitude__s)},  
                                    longitude: {!if(Location__c.Geo_Location__Longitude__s==null,78.38132679614262,Location__c.Geo_Location__Longitude__s)}  
                                    },  
                               radius: 100,  
                               onchanged: function (currentLocation, radius, isMarkerDropped) {  
                                    var addressComponents = $(this).locationpicker('map').location.addressComponents;  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Address').val(addressComponents.addressLine1);  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:City').val(addressComponents.city);  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Province').val(addressComponents.stateOrProvince);  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Zip').val(addressComponents.postalCode);  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Country').val(addressComponents.country);  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Latitude').val($(this).locationpicker('map').location.latitude);  
                                    $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Longitude').val($(this).locationpicker('map').location.longitude);  
                               }  
                          });  
                     </script>  
                </apex:pageblocksection>  
           </apex:pageblock>  
      </apex:form>  
 </apex:page>  

Most of the code is Visualforce Markup. All tags used in it are basic default ones used for building a form. Most of the tags are self explanatory by their names.  Lets understand some important tags we used in above code along with the Javascript.

As mentioned in problem statement, we are creating Visualforce page for a custom object 'Location__c' as mentioned in 'StandardController' attribute of 'Page' tag.

 <apex:pageblockbuttons >  
      <apex:commandbutton action="{!save}" value="Save"></apex:commandbutton>  
      <apex:commandbutton action="{!cancel}" value="Cancel"></apex:commandbutton>  
 </apex:pageblockbuttons>  

Command buttons are the action buttons displayed for a page on top and bottom of the form. We added the default 'Save' and 'Cancel' actions provided for any object by Salesforce.

 <apex:pageblocksection id="AddressInformationPBS" title="Address Information">  
      <apex:inputfield value="{!Location__c.Address__c}" id="Address" ></apex:inputfield>  
      <apex:inputfield value="{!Location__c.Zone__c}" ></apex:inputfield>  
      ......
 </apex:pageblocksection>  

From above code we can understand that we are using 8 custom fields in the 'Location' Custom object to store the detailed address information of the location.
 
'InputField' tag automatically displays the corresponding control of the field , along with data if it is used in edit screen.

 <script>  
      $('#map').locationpicker({  
           location: {    
                latitude: {!if(Location__c.Geo_Location__Latitude__s==null,17.4512887508432,Location__c.Geo_Location__Latitude__s)},  
                longitude: {!if(Location__c.Geo_Location__Longitude__s==null,78.38132679614262,Location__c.Geo_Location__Longitude__s)}  
                },  
           radius: 100,  
           onchanged: function (currentLocation, radius, isMarkerDropped) {  
                var addressComponents = $(this).locationpicker('map').location.addressComponents;  
                $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Address').val(addressComponents.addressLine1);  
                $('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:City').val(addressComponents.city);  
                ...
           }  
      });  
 </script>  

Above script is the default configuration of the 'Jquery Locationpicker' plugin. You can understnad more about this plugin  at this link, Jquery Locationpicker

Most important code to understand in above block is accessing fields.

$('#LocationPage\\:FormLocation\\:locationPB\\:AddressInformationPBS\\:Address').val('...');

In Salesforce, for a HTML Control, DOM Id is generated dynamically. A control ID has all the parent sections' IDs hierarchically with colon ( : ) separated. 

So, in our above example, HTML rendered ID of a control ( Client side ID ) is

"Page ID:Form ID:PageBlock ID:PageBlockSection ID:Control ID"

If you are adding any extra section or removing some section, ensure these blocks are updated.

Now, you can set this page as default New / Edit form by overriding the existing buttons in the 'Location' Object. This can be accomplished using below steps,

  1. Login to Salesforce
  2. Under Logged in User name drop down, select 'Setup'
  3. In left navigation, under 'App Setup' section go to 'Create' and then 'Objects'
  4. All the custom objects are listed. Click on 'Location' object
  5.  Go to 'Buttons, Links and Actions' section and Edit the existing buttons 'New' and "Edit'
  6. Now Choose 'Visualforce Page' radio option and select the newly created page from the drop down and save it.
Now when you click on New or Edit record of Locations, screen will be displayed as below.
Try changing the point displayed in map. It automatically updated above fields. Now user can change is any information to be updated and then save it accordingly.

Tuesday, December 30, 2014

Chrome Extension, explained with Simple example

After using many Chrome extensions and Apps, I thought of writing an extension on my own. But couldn't try it as I felt it might be difficult and need to learn many other concepts / languages related to it. Recently I tried and realized that my assumptions on it were wrong. Its too simple and we don't need to learn any new concepts to implement it except few configuration options.

So, to start with a basic extension, lets go with below example,

For a Chrome extension, manifest file is mandatory. It provides information about the extension. It acts as a configuration file for our extension. Its in JSON format. There are lots of options / fields available, to understand each check out at Google site  . In our sample we used 5  fields as in below code.
 {  
  "name": "SampleExtension",  
  "manifest_version":2,  
  "version": "0.1.1",  
  "description": "Sample extension, changes title and main image in a wiki article",  
  "content_scripts": [  
   {  
    // list websites in whcih you want to execute this extension
    "matches": ["http://en.wikipedia.org/wiki/*"], 
    //CSS and javascript resources we use 
    "css": ["styles.css"],  
    "js": [ "jquery.min.js","contentscript.js"]  
   }  
  ]  
 }  

Lets understand each field we used in above code


  • Name: this is the name of the extension and it comes in Extensions list once installed
  • Manifest-Version: this is the manifest file format version. and it should be 2 as 1 is deprecated
  • Version: version of our extension
  • Description: Description about the extension
  • Content_scripts: This provides core functionality information of the extension
    • matches: List all the websites in which our extension should execute
    • css: CSS files if we are using any
    • js: JS resource files if we are using in our extension
Copy the above code and paste in a new file and save it into a seperate folder with name 'manfiest.json'. Note the format is 'JSON'.

As we see in above code, we specified 3 resources, of which 1 is CSS and other 2 are javacript files
We need to create those files and save them in the same folder we have 'manifest.json'

In my sample, CSS file code is as below,
 #firstHeading span  
 {  
      color:red;  
 }  

And, code for 'contentscript.js' is,
 $(document).ready(function(){  
 $('#firstHeading span').html('My Custom Name using Extension');  
 $('.infobox.vcard img').first().attr('src','http://cdns2.freepik.com/free-photo/boy-face-cartoon-clip-art_430749.jpg');  
 });  

Don't forget to add the other Jquery file which you find on google.

Now our extension is ready. To, test it in you local machine,

  1. Go to Extensions of Chrome which is available in settings 
  2. Check 'Developer Mode' select box available on top.
  3. Once you check, 'Load Unpackaged Extension..' button will be displayed.
  4. Click on it and provide the folder which has above 4 files
  5.  Now the extension is loaded and enabled as in below image
  6. TO test it open wiki page of any person or any article. you will see the title changed and also the article main image(if available) is changed



Friday, December 26, 2014

Display maps in Salesforce Record View screen

Problem Statement:  
  We have a Custom Object to maintain 'Shipment details', which has 'To Address' and 'From Address' details along with other information in Salesforce.We need to display these details on a Map along with other information in the Detailed screen.

Approach we Used:
 Its very easy to display it on maps. We followed below steps to implement it.
  1.  Create a Visualforce Page  to display map using Google Maps API with Javascript.
    1. To create new Visual page, click on setup, then in left navigation pane, go to Build > Develop > Pages
    2. List of all Visual pages are displayed. Click on New and provide required fields
    3. Now, paste below code in the Markup Block
        
         
       <apex:page standardController="<<Custom Object API Name>>">  
       <apex:pageBlock >  
       <script src="https://maps.googleapis.com/maps/api/js?v=3.exp"></script>  
       <script>  
            var directionsDisplay;  
            var directionsService = new google.maps.DirectionsService();  
            var map;  
            function initialize() {  
             directionsDisplay = new google.maps.DirectionsRenderer();  
             var chicago = new google.maps.LatLng(41.850033, -87.6500523);  
             var mapOptions = {  
                 zoom:7,  
                 center: chicago  
             };  
             map = new google.maps.Map(document.getElementById('map'), mapOptions);  
             directionsDisplay.setMap(map);  
             var request = {  
                  origin:new google.maps.LatLng({!<<Custom Object API Name>>.From_Geo_Location__Latitude__s}, {!<<Custom Object API Name>>.From_Geo_Location__Longitude__s}),  
                  destination:new google.maps.LatLng({!<<Custom Object API Name>>.To_Geo_Location__Latitude__s}, {!<<Custom Object API Name>>.To_Geo_Location__Longitude__s}),  
                  travelMode: google.maps.TravelMode.DRIVING  
             };  
             directionsService.route(request, function(response, status) {  
                 if (status == google.maps.DirectionsStatus.OK) {  
                  directionsDisplay.setDirections(response);  
                 }  
             });  
            }  
            google.maps.event.addDomListener(window, 'load', initialize);       
       </script>  
       <div style='height:230px;width:100%'>  
         <div class='map' id="map"></div>  
       </div>  
       </apex:pageBlock>  
       </apex:page>  
      
    4. For Origin and Destination values in above code we provided the latitude and longitude coordinates of the data stored in the record
    5. Save the page.
  2.  This page will be listed in the layout screen of the custom object for which we are creating
  3. Add this page into any section of layout where we want to display.
  4. To add this, Click on Setup, in left navigation pane, go to Create > Objects
  5. All the custom objects are displayed, select the Object on which we are working and go to 'Page Layouts' section and click Edit 
  6. Add a new section and drop the listed page into it and Save.
  7. Now click on any record of the custom object to see the map we added with directions between the 2 locations of the same reord


Friday, December 12, 2014

Conditional Formatting in Sharepoint 2010


Problem Statement:  
  In a task list, we need to change background color of critical column based on its value and also the status (another field value)

Approach we Used: 
We have Conditional Formatting option in the designer using which we can set styles and also display the content based on conditions

Explanation with Example:
Step1: Open site in the designer and open one view.aspx file of a list that you need formatting

Step 2: In the View tab of designer, we have Task Panes, in that select conditional Formatting.


Step 3: Now select one cell content in the column on which we need formatting.
                Eg: On top, in critical section I selected yes word.

Step 4: Then Conditional Formatting section is highlighted, and then click on Create dropdown button which is in Conditional Formatting section



Step 5: You can see 3 options available, Show content, Hide Content, Apply Formatting, choose any one.
                Eg: I have chosen Apply Formatting




Step 6: Then we get conditional Criteria window, in which we set condition.
                Here you can group conditions, and as you can see, select field name in the list and we can compare to some value for equal or other etc. We even have advanced to have complex conditions

Step 7: Now after you complete preparing condition, click on set style which means, this style which we put is applied on the column items which we selected in the starting if the given condition is satisfied

Step 8: Now style window is opened in which we can set our style we need. Finally click on Ok, to finish our work.

We can see the condition created in the Conditional Formatting section which you can select it and modify further.

Similarly we can hide or show content based on conditions.


Done.

Wish it helps you