Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Info
Excerpt

This tutorial demonstrates advanced capabilities of ConfiForms app and it's APIs and shows you how to build a "non boring" forms for collecting user's feedback


We at Vertuna LLC, live, eat and breath data entry forms, we just love to build forms to quickly collect user opinions and feedback. And we love Atlassian products, so we have built, and continue to build, the best forms add-on for app for Confluence available on Atlassian Marketplace called - ConfiForms, Data entry forms and workflows.

...

We want something more sexy and user engaging. So, we will build a user macro with icons and a little bit of scripting to glue the things together.

Image Added

When a form is used by an authenticated user then this information is stored in the createdBy field, as ConfiForms has some metadata fields stored with each record (even when you have defined just one field, as we did in this example)

When a form is used by anonymous users the createdBy field is left blank


Each image has a custom "onClick" handler and invokes ConfiForms REST API to create new record in the form

The code, the handler invokes, looks something like this:

## @param FormName:title=Form name|type=string|required=true|desc=ConfiForms Form name ## @param Page:title=Page|type=confluence-content|required=true|desc=Select a page where ConfiForms Form is located ${paramPage} #set( $cfPageId = $content.id) #if(${paramPage}) #set( $spaceAndPageTitle = $paramPage.split(":")) #set( $pageTitle = $paramPage) #set( $spaceKey = $content.spaceKey) #if ($spaceAndPageTitle.length() == 2) #end #set( $cfPageId = $pageManager.getPage($spaceKey, $pageTitle).getId()) #end <table class="wrapped cf_quickfeedback_$!{paramFormName}" style="border: 0;"> <colgroup> <col/> <col/> <col/> <col/> </colgroup> <tbody> <tr style="border: 0;"> <td style="border: 0;"> <div class="content-wrapper user-choice-cf"> <p> <img alt="Awesome" style="cursor: pointer" data-choice="1" width="50px" src="data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDQ3My45MzEgNDczLjkzMSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDczLjkzMSA0NzMuOTMxOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Y2lyY2xlIHN0eWxlPSJmaWxsOiNGRkMxMEU7IiBjeD0iMjM2Ljk2NiIgY3k9IjIzNi45NjYiIHI9IjIzNi45NjYiLz4NCjxwYXRoIHN0eWxlPSJmaWxsOiNGRkZGRkY7IiBkPSJNODEuMzkxLDIzNy4xMjNjMCw4NS45MTEsNjkuNjQ5LDE1NS41NiwxNTUuNTYsMTU1LjU2Yzg1LjkxNSwwLDE1NS41NjQtNjkuNjQ5LDE1NS41NjQtMTU1LjU2DQoJTDgxLjM5MSwyMzcuMTIzTDgxLjM5MSwyMzcuMTIzeiIvPg0KPGc+DQoJPHBhdGggc3R5bGU9ImZpbGw6I0NDQ0JDQjsiIGQ9Ik0xNjcuNzI4LDIzNy4xMjNjMCw0Ni40MzUsMCw5Mi44NywwLDEzOS4zMDZjNi4wMjQsMy4wMDEsMTIuMjczLDUuNjA5LDE4LjcwOSw3LjgyDQoJCWMwLTQ5LjA0MywwLTk4LjA4MywwLTE0Ny4xMjZIMTY3LjcyOHoiLz4NCgk8cGF0aCBzdHlsZT0iZmlsbDojQ0NDQkNCOyIgZD0iTTI4My4zMTksMjM3LjEyM2MwLDQ5LjUxMSwwLDk5LjAxOCwwLDE0OC41MjljNi40MzItMi4wMDYsMTIuNjY2LTQuNDUzLDE4LjcwOS03LjI0DQoJCWMwLTQ3LjA5OCwwLTk0LjE5MSwwLTE0MS4yODlMMjgzLjMxOSwyMzcuMTIzTDI4My4zMTksMjM3LjEyM3oiLz4NCjwvZz4NCjxnPg0KCTxwYXRoIHN0eWxlPSJmaWxsOiMzMzMzMzM7IiBkPSJNMjE5LjE4MSwxNTguNzkzYy0xLjY4NC0zMS4yNTUtMjMuOTkyLTUzLjU2LTU1LjI0My01NS4yNDMNCgkJYy0zMS4xODQtMS42OC01My42OTgsMjYuNTIyLTU1LjI0Myw1NS4yNDNjLTAuNjUxLDEyLjA2MywxOC4wNjEsMTIsMTguNzA5LDBjMi41MzctNDcuMDksNzAuNTM2LTQ3LjA5LDczLjA2OSwwDQoJCUMyMDEuMTIsMTcwLjc5MywyMTkuODMyLDE3MC44NTYsMjE5LjE4MSwxNTguNzkzTDIxOS4xODEsMTU4Ljc5M3oiLz4NCgk8cGF0aCBzdHlsZT0iZmlsbDojMzMzMzMzOyIgZD0iTTM1My45ODUsMTU4Ljc5M2MtMS42ODQtMzEuMjU1LTIzLjk5Mi01My41Ni01NS4yNDMtNTUuMjQzDQoJCWMtMzEuMTg0LTEuNjgtNTMuNjk0LDI2LjUyMi01NS4yNDMsNTUuMjQzYy0wLjY1MSwxMi4wNjMsMTguMDYxLDEyLDE4LjcwOSwwYzIuNTM3LTQ3LjA5LDcwLjUzMi00Ny4wOSw3My4wNjksMA0KCQlDMzM1LjkyNCwxNzAuNzkzLDM1NC42MzcsMTcwLjg1NiwzNTMuOTg1LDE1OC43OTNMMzUzLjk4NSwxNTguNzkzeiIvPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=" /> </p> </div> </td> <td style="border: 0;"> <div class="content-wrapper user-choice-cf"> <p> <img alt="Good" style="cursor: pointer" data-choice="2" width="50px" src="data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDQ3My45MzUgNDczLjkzNSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDczLjkzNSA0NzMuOTM1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Y2lyY2xlIHN0eWxlPSJmaWxsOiNGRkMxMEU7IiBjeD0iMjM2Ljk2NyIgY3k9IjIzNi45NjciIHI9IjIzNi45NjciLz4NCjxnPg0KCTxjaXJjbGUgc3R5bGU9ImZpbGw6IzMzMzMzMzsiIGN4PSIxNjQuOTM4IiBjeT0iMTU1LjIzMiIgcj0iMzcuMjE2Ii8+DQoJPGNpcmNsZSBzdHlsZT0iZmlsbDojMzMzMzMzOyIgY3g9IjMwNS42NjciIGN5PSIxNTUuMjMyIiByPSIzNy4yMTYiLz4NCgk8cGF0aCBzdHlsZT0iZmlsbDojMzMzMzMzOyIgZD0iTTM0My4yNTcsMzE2Ljg2MmMtNTkuMjgxLDYwLjMyOS0xNTQuNjYzLDU5Ljg1NC0yMTMuNDUtMC44OTgNCgkJYy04LjQtOC42ODUtMjEuNjE2LDQuNTYxLTEzLjIyNywxMy4yMjdjNjUuNzY5LDY3Ljk3LDE3My42NDUsNjguMzQsMjM5LjkwNSwwLjg5OA0KCQlDMzY0Ljk0NCwzMjEuNDc5LDM1MS43MjEsMzA4LjI0NSwzNDMuMjU3LDMxNi44NjJMMzQzLjI1NywzMTYuODYyeiIvPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=" /> </p> </div> </td> <td style="border: 0;"> <div class="content-wrapper user-choice-cf"> <p> <img alt="Could be better" style="cursor: pointer" data-choice="3" width="50px" src="data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDQ3My45MzUgNDczLjkzNSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDczLjkzNSA0NzMuOTM1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Y2lyY2xlIHN0eWxlPSJmaWxsOiNGRkMxMEU7IiBjeD0iMjM2Ljk2NyIgY3k9IjIzNi45NjciIHI9IjIzNi45NjciLz4NCjxnPg0KCTxwYXRoIHN0eWxlPSJmaWxsOiMzMzMzMzM7IiBkPSJNMzU2LjY3MSwzNTQuMWMtNjYuMjI2LTY3LjYxOC0xNzQuMjU1LTY3LjMzNy0yNDAuMDk2LDAuNzAzDQoJCWMtOC4zODksOC42NjYsNC44MjcsMjEuOTEyLDEzLjIyNywxMy4yMjdjNTguODctNjAuODMsMTU0LjM4Ni02MS4yMDQsMjEzLjY0MS0wLjcwM0MzNTEuODk2LDM3NS45NiwzNjUuMTE2LDM2Mi43MjEsMzU2LjY3MSwzNTQuMQ0KCQlMMzU2LjY3MSwzNTQuMXoiLz4NCgk8Y2lyY2xlIHN0eWxlPSJmaWxsOiMzMzMzMzM7IiBjeD0iMTY0LjkzOCIgY3k9IjE1NS4yMzIiIHI9IjM3LjIxNiIvPg0KCTxjaXJjbGUgc3R5bGU9ImZpbGw6IzMzMzMzMzsiIGN4PSIzMDUuNjY3IiBjeT0iMTU1LjIzMiIgcj0iMzcuMjE2Ii8+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8L3N2Zz4NCg==" /> </p> </div> </td> <td style="border: 0;"> <div class="content-wrapper user-choice-cf"> <p> <img alt="WTF!?" style="cursor: pointer" data-choice="4" width="50px" src="data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDQ3My45MzUgNDczLjkzNSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNDczLjkzNSA0NzMuOTM1OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Y2lyY2xlIHN0eWxlPSJmaWxsOiNGRkMxMEU7IiBjeD0iMjM2Ljk2NyIgY3k9IjIzNi45NjciIHI9IjIzNi45NjciLz4NCjxnPg0KCTxwYXRoIHN0eWxlPSJmaWxsOiMzMzMzMzM7IiBkPSJNMzU3LjMxOCwzNTQuOGMtNjYuMDg0LTY4LjI5MS0xNzQuNjYzLTY4LjI4OC0yNDAuNzQzLDAuMDA3DQoJCWMtOC4zODksOC42NjYsNC44MjcsMjEuOTEyLDEzLjIyNywxMy4yMjdjNTkuMTM5LTYxLjExOCwxNTUuMTQ2LTYxLjEyMiwyMTQuMjg4LTAuMDA3DQoJCUMzNTIuNDkxLDM3Ni43MDgsMzY1LjcxMSwzNjMuNDY2LDM1Ny4zMTgsMzU0LjhMMzU3LjMxOCwzNTQuOHoiLz4NCgk8Y2lyY2xlIHN0eWxlPSJmaWxsOiMzMzMzMzM7IiBjeD0iMTY0LjkzOCIgY3k9IjE5Mi42NjUiIHI9IjM3LjIxNiIvPg0KCTxjaXJjbGUgc3R5bGU9ImZpbGw6IzMzMzMzMzsiIGN4PSIzMDUuNjY3IiBjeT0iMTkyLjY2NSIgcj0iMzcuMjE2Ii8+DQoJPHBhdGggc3R5bGU9ImZpbGw6IzMzMzMzMzsiIGQ9Ik0zMTYuMzY0LDY4LjM4OWMtMjguNjc3LDI4LjY3My01Ny4zNSw1Ny4zNS04Ni4wMjQsODYuMDI0YzQuNDA4LDAsOC44MTksMCwxMy4yMjcsMA0KCQljLTI4LjY3My0yOC42NzctNTcuMzQ3LTU3LjM1LTg2LjAyLTg2LjAyNGMtOC41MzktOC41MzktMjEuNzY2LDQuNjg4LTEzLjIyNywxMy4yMjdjMjguNjczLDI4LjY3Nyw1Ny4zNDcsNTcuMzUsODYuMDIsODYuMDI0DQoJCWMzLjYwMywzLjYwMyw5LjYyNCwzLjYwMywxMy4yMjcsMGMyOC42NzctMjguNjczLDU3LjM1LTU3LjM1LDg2LjAyNC04Ni4wMjRDMzM4LjEzLDczLjA3NywzMjQuODk5LDU5Ljg0NiwzMTYuMzY0LDY4LjM4OQ0KCQlMMzE2LjM2NCw2OC4zODl6Ii8+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8L3N2Zz4NCg==" /> </p> </div> </td> </tr> </tbody> </table> <div id="thankumsg_$!{paramFormName}" style=" display:none"> <div class="aui-message aui-message-info closeable shadowed success"> <p>Thank you for your feedback</p> </div> </div> #set( $D = '$' ) #set( $serverUrl = 'AJS.params.contextPath' ) #set( $ajaxCall = 'AJS.$.ajax({url: AJS.params.contextPath + "
/ajax/confiforms/rest/save.action?pageId=
'+${cfPageId}+'
16646199&f=
'+$!{paramFormName}+'
f&choice=
"
' + 
dc
mychoice,
      type: "GET",
success: function() { AJS.$("#thankumsg_'+$!{paramFormName}+'").show(); window.setTimeout(function () { AJS.$("#thankumsg_'+$!{paramFormName}+'").fadeOut("slow");}, 2000);}});') <script type="text/javascript"> AJS.toInit(function() { AJS.$D('.cf_quickfeedback_$!{paramFormName}').find('img').click(function() { var dc = AJS.$D(this).attr('data-choice');

      success: function (data) {
       // here we need to tell we received the feedback
      
${ajaxCall
}
    });
  }
);


</script>
Code Block
 // mychoice is the value (ID) for each option in "choice" field

 function leaveFeedback(mychoice) {
    AJS.$.ajax({
      url: 'https://wiki.vertuna.com
Expand
titleUser macro source code
Code Block

When a form is used by an authenticated user then this information is stored in the createdBy field, as ConfiForms has some metadata fields stored with each record (even when you have defined just one field, as we did in this example)

See more complete example on how to setup the handlers with scripting here: Custom feedback form with ConfiForms and some JavaScript


You can also see the form in action and user macro created for you

Children Display
When a form is used by anonymous users the createdBy field is left blank


What is good about ConfiForms is that you can use and re-use the defined form on multiple pages, as well as build the "views" around the stored data where you want. Let's build the table over the stored data, we will show the metadata field created with the feedback given

This is as simple as this, thanks to ConfiForms TableView macro

Image Added

And the result would be something like this

Created

User feedback

Oct 06, 2017 16:06Awesome
Oct 06, 2017 16:06Could be better
Oct 06, 2017 16:06WTF!?
Oct 06, 2017 16:06Good
Oct 06, 2017 16:06Awesome
Oct 06, 2017 16:06Could be better
Oct 06, 2017 16:06Awesome

Of course we can add some styling to the table, and can show other fields stored (like the mentuioned earlier createdBy metadata field) or with modifying the form definition a little bit further we can collect some system environment data, see notes on the bottom of this page.


Also, to have a good overview of the data stored we will make a simple report using Confluence built in chart macro and will group the choices made by our users and present the aggregated data as a pie chart

Awesome

Good

Could be better

WTF

3121


Image RemovedImage Added

All in real time, rendering the chart based on the data stored, by using ConfiForms Table View Merger macro together with Confluence Chart macro

...