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.
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; } } |
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) ); }); }); } |
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.
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}); }); }); } |
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.
war
.
Make sure the folder name is 'resources', Jello will look for this name.../jello/resource/<module-jar-file-name>/the-resource-fileChange 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}); }); }); } |
jar
file named 'com.company.jello.module.feedback.jar'.
Your module jar file should look like this: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> |
Was this page helpful? Let us know how we did:
Last updated January 1, 2016.