Jello framework

Collecting feedback from your site visitors can be very useful. Let's say you want to add a feedback widget to some of the pages in your site, similar to the one on the bottom of this page.

To keep it simple, we will use a rating control with one digit rating score, from 1 - 'Unusable document' to 5 - 'Excellent document'. Whenever a visitor rates the page, we will send the score together with the relevant page path.

feedback widget

Write the Feedback entity

The rating widget

Adding the widget to each page

Throwing a cookie into the party

Take it to next level - warp it as a Jello Module



First thing, let's write the Feedback entity

We want to store the page path and its score. These values will be sent by the page, using an OData POST request to create a new record. In addition, we want to store the IP address of the request and, if the visitor is logged in, the user's email address as well.

Any visitor, whether a guest or an authenticated user, is allowed to send feedback. In our implementation, that means anyone should have the privilege to create a Feedback record. Once created, only the site administrator (that's you) has access to this record.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package analytics;

@PersistenceCapable
@Accessible(
   create = Role.ALL, 
   delete = Role.ADMIN, 
   query = Role.ADMIN, 
   retrieve = Role.ADMIN, 
   update = Role.ADMIN 
)
public class Feedback extends JelloEntity {
   @Expose @Required
   public String page;

   @Expose @Required
   public Integer rating;

   @Expose
   public String user;
   
   @Expose
   public String ip;   

   @Override
   protected JelloEntity beforeSave() throws IllegalRequestResource {
      ip = Util.getCurrentRequestClientID();
      UserService uservice = UserServiceFactory.getUserService();
      if(uservice.isUserLoggedIn()) {
         user = uservice.getCurrentUser().getEmail();
      }   
      return this;
   }
}


new feedback entity dialog

Next, we need a rating widget and a JavaScript function to handle the widget's life cycle on each page.

Jello is not about custom UI, so you will have to use all of your JavaScript skills here. Luckily, we already showed how to implement a custom rating control based on a 3rd party open source (JQuery Raty). In this tutorial, we will use the rating control from the custom controls tutorial.

Note how we use the JQuery require plugin. This will load the rating control file (and all its dependencies) asynchronously. The idea here is to encapsulate all the required resources so we will not need to manually include them in each page. We will take this 'Reducing the build of materials' concept one step farther in the last step of this tutorial.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
function addFeedback(containerId) {
   containerId = containerId || "feedback";
   
   require(['/path-to-control-file/RatingControl.js'], function() {
      var settings = {
         hints : ['Unusable document', 'Poor document', 'OK document', 'Good document', 'Excellent document']
      }
      
      var ratingCtrl = new RatingControl(containerId, settings);
      ratingCtrl.render();
           
      ratingCtrl.change( function(evt, ctrl, score) {
           var payloud = {page: location.pathname, rating: score};
           
           var xhttp = new XMLHttpRequest(); 
           xhttp.open("POST", "/jello/data/analytics/Feedback", true);
           xhttp.send( JSON.stringify(payloud) );               
        });
   });
}


Finally, we need to add the widget to each page.

All that is left to do is simply add an empty div to each page and call the addFeedback() method. That is it! you have just added a shiny feedback control to your page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<p>Was this page helpful? Let us know how we did:</p>
<div id="feedback"></div>

<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src='path-to-file/requirejs-2.1.20/require.min.js'></script>

<script type="text/javascript">
   jQuery(document).ready(function() {
      addFeedback(); 
   });
</script>

Try it out:
Click on one of the stars to rate your page and check to see how the score has been saved in the database.

feedback entity view

The current implementation will add a new record each time the user rates the page. That's fine, we would like to know if a user changes their mind... But it would be nice if we could show the user the last known rating in case they forgot they have already rated this page. That can be easily done by saving the last score in a cookie. Here we use a JQuery cookie open source plugin.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function addFeedback(containerId) {
   containerId = containerId || "feedback";
   
   require(['/path-to-control-file/RatingControl.js'], function() {
      var settings = {
         hints : ['Unusable document', 'Poor document', 'OK document', 'Good document', 'Excellent document']
      }
      
      var ratingCtrl = new RatingControl(containerId, settings);
      
      ratingCtrl.render( function(ctrl) {
         var score = $.cookie('feedback');
         if( score ) {
            ctrl.setValue( score );
         }
      });
           
      ratingCtrl.change( function(evt, ctrl, score) {
           var payloud = {page: location.pathname, rating: score};
           
           var xhttp = new XMLHttpRequest(); 
           xhttp.open("POST", "/jello/data/analytics/Feedback", true);
           xhttp.send( JSON.stringify(payloud) );    
           
           $.cookie('feedback', score, {path: window.location.pathname});
        });
   });
}


Take it to the next level, wrapping everything together as reusable Jello Module

You probably feel so cool with your new Feedback widget and entity and now you want to use it in all of your projects. Maybe even to wrap and release it as a reusable component...

Just to recap all of the different files we needed. The Bill Of Materials will look like this:
- analytics package
-- Feedback.java
- RatingControl.js
- addFeedback function
- Raty control plugin library

Wrapping everything together in one reusable component is what you are looking for. Jello supports exactly that concept. Jello Module is a jar file that contains all the resources needed for your reusable component.

  1. Create a new Jello project. You can call it, let's say 'MyJelloFeedbackModule' and copy the Feedback entity to it.
  2. You might want to have a globally unique namespace. How about com.company.analytics? Rename the Feedback page to your preferred namespace.
  3. Copy all the resources (js, css, plugins folders...) to a new resources folder under war. Make sure the folder name is 'resources', Jello will look for this name.
  4. Any resource located under the module's resources folder is accessible using the following path prefix schema:
    ../jello/resource/<module-jar-file-name>/the-resource-file
    Change the resources path accordingly.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    if (typeof $company == 'undefined') {
       $company = {};
    }
    
    $company.addFeedback = function(containerId) {
       containerId = containerId || "feedback";
       
       require(['/jello/resource/com.company.jello.module.feedback/RatingControl.js'], function() {
       
       ...
          
       ratingCtrl.change( function(evt, ctrl, score) {
               var payloud = {page: location.pathname, rating: score};
               
               var xhttp = new XMLHttpRequest(); 
               xhttp.open("POST", "/jello/data/com.company.analytics/Feedback", true);
               xhttp.send( JSON.stringify(payloud) );    
               
               $.cookie('feedback', score, {path: window.location.pathname});
            });
       });
    }
    

  5. Export the project to a jar file named 'com.company.jello.module.feedback.jar'. Your module jar file should look like this:
    feedback module file tree
  6. Copy the new feedback module jar file to the target project where you want to use it. It should go under war » WEB-INF » lib.
    feedback module lib tree
  7. That is it! Your new module is ready to serve. You can check to see if it appears on the application document (http://<host>/jello).
    feedback widget Just include the relevant js file in your page and call the addFeedback() function.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    <p>Was this page helpful? Let us know how we did:</p>
    <div id="feedback"></div>
    
    <script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src='path-to-file/requirejs-2.1.20/require.min.js'></script>
    
    <script src="/jello/resource/com.company.jello.module.feedback/feedback.js"></script>
    
    <script type="text/javascript">
       jQuery(document).ready(function() {
           $company.addFeedback(); 
       });
    </script>
    


Last updated January 1, 2016.