Recipe to add AJAX, dynamic ratings in Salesforce using jQuery.


We all like to see our clients rejoice when we create great user experiences (UX) – JavaScript has helped us a lot in achieving this. By considering a scenario in Apex and Visualforce development, I’d like to show you how to add rating (1-5 scale) using jQuery with custom logic to save the relevant ratings in a separate object, and load it dynamically!

Utensils required

  1. Salesforce Environment.
  2. jQuery library.
  3. 2 icons to show the rating.

Ingredients

  1. One parent object (standard or custom, I am using “Account” object).
  2. One child custom object (I have created custom object called “Rating”).
  3. Two Apex Classes (one for the controller and another for test class).
  4. One Inline visualforce page.
  5. Two Static Resources

Demo: click here to taste!

Method

Step one: Create Metadata

Create a custom object called “Rating” with following fields;

  1. Standard field “Name” with type as “Auto number” and a format of “R-{0000}”
  2. Custom field with name as “Account”, type as “Master-Detail” and relationship to “Account” object.
  3. Custom field with name as “Rated By”, type as “Look-Up” and relationship to “User” object.
  4. Custom field with name as “Scale”, type as “Number”, length as 1 and decimal places 0

Check the below screenshot for all details:

Now add some fields to “Account” object;

  1. Create a custom field called “Number of Ratings” with type as “Roll Up Summary”, summary type as “COUNT”, Summarised object to “Rating”.
  2. Create a custom field called “Total Ratings” with type as “Roll Up Summary”, summary type as “SUM”, Summarised object to “Rating” and field to aggregate is “Scale”.
  3. Create a custom formula field called “Average Ratings” with type as “number” and formula as “ROUND( Total_Ratings__c / Number_of_Ratings__c , 0)” and 0 decimal place.

Step two: Create apex and visualforce code

  1. Create Custom controller with a name “Rating” with a code below;
public with sharing class Rating {

// Define the constructor
public Rating(ApexPages.StandardController controller) {
Account co = (Account)controller.getRecord();
account_id = co.id;
}

// Define the variables
public string account_id = ApexPages.currentPage().getParameters().get('Id');
private integer current_rating;
private Rating__c ratingObj = new Rating__c();
private integer stored_val;
/*
* Load the average rating when the record is loaded, It works irrespective of the current user has not rated the record.
* No average rating so far? make it to zero(0)
*/

public integer storedVal{
get{
try {
Account accountObj = [SELECT Average_Ratings__c FROM Account WHERE Id = : account_id];
stored_val = Integer.valueOf(accountObj.Average_Ratings__c);
}catch(QueryException e) {
stored_val = 0;
}
if(stored_val == null)
stored_val = 0;

return stored_val;
}
}

/*
* If the user has already rated the account then retreive it and show!
*/

public integer currentRating{
get {
if (current_rating == null) {
try {
ratingObj = [SELECT Scale__c, Rated_By__c FROM Rating__c WHERE Account__c = : account_id AND Rated_By__c = :UserInfo.getUserId()];
current_rating = Integer.valueOf(ratingObj.Scale__c);
}catch(QueryException qe){
current_rating = 0;
ratingObj.Rated_By__c = UserInfo.getUserId();
ratingObj.Account__c = account_id;
}
}
return current_rating;
}
set {
current_rating = value;
}
}
/*
* Method being called from the jquery to submit the rating into the database.
*/

public void submit() {
ratingObj.Scale__c = currentRating;
upsert ratingObj;
}
}
  1. Add these 2 static resources;  and   with names as “Like_Thumb” and “Black_White_Thumb” respectively.
  2. Create visualforce page with a name “Rating” and a standard controller as “Account” and “Rating” as an extension.
<apex:page standardController="Account" extensions="Rating">
<apex:form >
<apex:outputPanel id="mainPanel">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"></script>
    <script>
    jQuery(document).ready(function($) {
        var storedValue = {!storedVal};
        setThumbs(storedValue); // load the average rating first.

        // When clicked, get the position of the thumb and submit it accordingly
        $(".thumb").click(function() {
            var rating = $(this).attr('rating');
            submitRating(rating);
        });
        // Hovering function to show colored and black&white thumbs depending on the cursor position.
        $(".thumb").hover(
            function() {
                var rating = $(this).attr('rating');
                setThumbs(rating);
            },
            function() {
                var storedValue = {!currentRating};
                setThumbs(storedValue);
            });
    });

    function setThumbs(rating){
        turnOnThumbs(rating);
        turnOffThumbs(rating);
    }

    function turnOnThumbs(rating){
        for(i=1; i<=rating; i++){
            var thumbId = '#thumb' + i;
            $(thumbId).attr('src', '{!$Resource.Like_Thumb}');
        }
    }
    function turnOffThumbs(rating){
        for(j=5; j>rating; j--){
            var thumbId = '#thumb' + j;
            $(thumbId).attr('src', '{!$Resource.black_White_Thumb}');
        }
    }

    </script>
    <div align="left">
    <img src="{!$Resource.Like_Thumb}" width="25" height="25" id="thumb1" rating="1"/>
    <img src="{!$Resource.Like_Thumb}" width="25" height="25" id="thumb2" rating="2"/>
    <img src="{!$Resource.Like_Thumb}" width="25" height="25" id="thumb3" rating="3"/>
    <img src="{!$Resource.Like_Thumb}" width="25" height="25" id="thumb4" rating="4"/>
    <img src="{!$Resource.Like_Thumb}" width="25" height="25" id="thumb5" rating="5"/>
     </div>
 </apex:outputPanel>

 <apex:actionFunction name="submitRating" action="{!submit}" reRender="mainPanel">
     <apex:param name="firstParam" assignTo="{!currentRating}" value=""/>
 </apex:actionFunction>

</apex:form>
</apex:page>
  1. Create a test class which tests above code;
@isTest

public class RatingTest {

static testMethod void verifyRatingTest(){

// Step1: Setup the data by inserting a record for test.

dataSetup();

Account aId = [SELECT Id FROM Account WHERE Name='Test Account'];

// Step2: Call the Standard Controller class using the above test data.

ApexPages.StandardController sc = new ApexPages.StandardController(aId);

// Test Case1: Assuming the default values, load the average rating, and with the 0 rating as current value, submit and do assertions. - Failure Test

Rating rt = new Rating(sc);

Integer strdValue = rt.storedVal;

Integer currValue = rt.currentRating;

rt.submit();

system.assertEquals(strdValue,0);

system.assertEquals(currValue,0);

// Test Case2: Now, Submit the current rating as 5 and expect the average rating to be 5 from assertions. - Pass Test.

rt.currentRating = 5;

rt.submit();

strdValue = rt.storedVal;

currValue = rt.currentRating;

system.assertEquals(strdValue,5);

system.assertEquals(currValue,5);

}

public static void dataSetup(){

Account testAccount = new Account(Name = 'Test Account');

insert testAccount;

}

}

Step Four: Enjoy the view

  1. Finally, add Inline visualforce page “Rating” to the “Account” object from the layout with the settings “Show label”, “100%” as width and  “20” as height.

Conclusion

You have given your user a nice bit of AJAX functionality by loading or submitting the data dynamically. Any suggestion/improvements most welcome!

Recipe by:  Irfan Khan – Developer Consultant at tquila

Tagged , , , , , , ,

14 thoughts on “Recipe to add AJAX, dynamic ratings in Salesforce using jQuery.

  1. Jiri says:

    Nice post Irfan.

  2. Irfan says:

    Thanks jiri! 🙂

  3. Stephen says:

    So it works just like the five star rating you have received at the top of the page!!

  4. Bashir says:

    This is awesome!!

  5. Nice recipe Irfan and thanks for sharing 🙂

  6. varma says:

    hey can u suggest me that i can see the thumbs but i cannot perform the action when was giving rating to it. please help me

    • Irfan says:

      There can be many possibilities on action not being performed,

      I would first add actionstatus to it (somewhere in the outputpanel)

      Also, would enable debug log to check if the ratings being updated in the database or is it just the values not being loaded from the database.

      Try dividing your problem into various chunks find out where is the actual problem.

      Cheers!

  7. varma says:

    actually it is just displaying the thumbs down only there is no other action to be performed.
    but u wrote a code that the ratings will get updated automatically. please solve this problem please please

  8. Irfan says:

    I cannot say anything until I see the code, I suggest you create a thread saying “With reference to this blog (and provide the link)” at developerforce forums http://boards.developerforce.com/ and share your visualforce page and controller code and later message me the link of that thread, this is my profile http://boards.developerforce.com/t5/user/viewprofilepage/user-id/51839

    • varma says:

      if u dont mind give me ur mail id i will provide my credintials to your mail. please

      • varma says:

        why i am asking means,i got a job in salesforce as a fresher, searching for the related code and today my task is like giving ratings to the image or anything else, and to be stored those ratings seperately…
        thats why i am asking ur email id. i will give the creditials to you

  9. Irfan says:

    Sorry dude, the point of sharing on the blog is that everyone benefits from the advice. I’d suggest that you create a public thread that links to this post on Force.com forums. You’ll get lots of help that way and others also benefit if they are seeking for the similar solution.

  10. Puneet Mehta says:

    Unfortunately, the click and hover function doesn’t seem to work. “.thumb” is not accessible? I’ve changed to
    any help?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: