Eating JavaScript Cookies with Adobe Captivate

cookiejar

Today we’re going to see how we can persist data across Captivate courses using JavaScript cookies.

Why cookies are so awesome

They let you store data that can be retrieved later… even days later.  For example:

  • You could use it to store the slide number where the user left off, then resume to that slide when they pick up the course again.
  • Store their name and retrieve it in another module “Welcome Back Jim!” to make the course more personable.
  • Display a dashboard showing which lessons have been completed in your course… even if they close the browser and come back again.
  • Store quiz scores from course to course, then average them out when they’re all complete displaying an overall score.
  • Gather information from users in survey-like fashion storing the information in a cookie.  Then make branching decisions in other courses based on their previous input.

 

Flexing Our JavaScript Muscles

I use a few JavaScript functions to help with creating, reading, and erasing cookies.  I keep most of my JavaScript (JS) inside the standard.js template file typically located at …\Adobe\Adobe Captivate 5.5\Templates\Publish. I’d strongly recommend backing up the original standard.js file.  I simply copied the file and renamed it standard_ORIG.js as my backup.  You can download my custom standard.js file with these functions already defined for you.  When you publish your .cptx project, Captivate will include this updated standard.js file with the new functions in your published output.

Download Project Files

 

Here’s the skinny on the func!  What’s in the standard.js file:

function storeCpVariable(cookieName, cpVariable, days) — stores the value of a Captivate variable in a cookie.  It takes three parameters:

      • cookieName = the name you want to give your cookie.
      • cpVariable = the name of the Captivate variable that contains the data you want to store.  The value of the Captivate variable will be stored in the cookie.
      • days = the number of days before the cookie expires.  If a number is not provided, the cookie will be erased upon browser exit.

function retrieveCpVariable(cookieName, cpVariable) — sets a Captivate user variable with a cookie’s retrieved value.

      • cookieName = the name you gave your cookie from a previous call to the storeCpVariable() function.
      • cpVariable = the name of the Captivate variable that you want to set.

 

Eat’em Up – Setting Cookies!

Using the functions is really quite simple.   You can add an “Execute JavaScript” action in Captivate from a slide entry or exit action, or from any interactive object (buttons, roll-over slidelets, click boxes, etc.)

image

In the above screenshot, we’re creating a cookie called ‘CookieDemo’, storing the value of the Captivate user variable ‘learnerName’, and setting the cookie to expire 2 days from now.  For example, let assume that the learnerName variable contained the value ‘Darli’.  Once the storeCpVariable() function is called, it will create a cookie named ‘CookieDemo’ and it will contain the value ‘Darli’, and it will expire 2 days from now.  If Darli came back to the course a day later, we could read that cookie and do something with her name.

 

Eat’em Up – Reading Cookies!

image

In this case, we are reading the cookie called ‘CookieDemo’ and we’re setting the Captivate variable ‘retrievedName’ with the retrieved cookie value.  Following our example, Let’s say Darli, our Learner, came back to the course the next day.  Once the retrieveCpVariable() function is called, the Captivate variable ‘retrievedName’ will be set to the retrieved cookie value ‘Darli’.  So if we had a caption in our Captivate project with “Welcome Back $$retrievedName$$“, at runtime it would read ‘Welcome Back Darli‘.

 

Practice — Try The Demo

*** Live Demo ***

Try entering your name and following all three steps.

Then erase the cookie by NOT entering your name and storing the empty value.  Then refresh the page.  You’ll notice the welcome message goes away because it’s conditional on the value of the cookie.  Welcome to a new world!

Download Project Files
Along with the two functions above, there are other “helper” functions in the standard.js file.  You don’t really need to use the below functions directly, but they’re good to know in case you want to break rank and do something unique:

function setCookie(name,value,days)  — This function creates cookies and updates them if you need to set a new value.  It takes three parameters:

      • name = the name you want to give your cookie
      • value = the info you want to store in your cookie
      • days = the number of days before the cookie expires.  If a number is not provided, the cookie will be erased upon browser exit.

function getCookie(name) — As you guessed, it will retrieve a cookie’s value.  It takes one parameter:  Then name of the cookie.  The same name you used in the setCookie() function.  Cookie names are case sensitive.

function eraseCookie(name) — BACK AWAY FROM THE COOKIE JAR!  Once you use this function, the cookie will be set to empty, then erased when the browser is closed.

         

  • http://twitter.com/marksiegrist Mark Siegrist

    Nice post, Jim. I have the misfortune of having to deploy Captivate projects solely through Adobe Connect’s “Training” module. Will have to try this to see if it works. I’m assuming it will.

    mark
    http://www.elearninglive.com

  • http://twitter.com/CaptivatePro CaptivateDev.com

    @Mark Siegrist:  Thanks for your comment Mark.  JavaScript cookies are client-side so it should work just fine.  Good luck with your project!

  • Jeremy Tart

    Where does the $$welcomeMsg$$ variable get set with the contents of the cookie in this?  I cannot seem to find it…

    • http://twitter.com/CaptivatePro CaptivateDev.com

      @google-c0d400e416e6c98a8406ff875c745787:disqus :  Should be on slide entry of the first slide.  The action is executing the following JS:

      function checkForCookie(){var objCP = document.Captivate;if(getCookie(‘CookieDemo’)){    objCP.cpEISetValue(‘welcomeMsg’, ‘Welcome Back ‘ + getCookie(‘CookieDemo’) + ‘!’);} else {    objCP.cpEISetValue(‘welcomeMsg’, ‘nnnnn.’);}}checkForCookie();

      • Jeremy Tart

        Ah, yes, I see that now… Thanks for the quick response.

        The trouble I am experiencing is that the storeCpVariable() function does not seem to be working for me, at least not in the way that I am trying to employ it.  I have set up multiple actions on a clickbox, and it seems that javascript that I execute in-line during a multiple action scenario isn’t firing. 

        The scenario is this: user clicks clickbox (transparent, over some other text), and I want a checkmark to appear and persist, even as the user is sent to another simulation.  I want that checkmark to remain when the user returns.  So on the clickbox object, I set up the following multiple actions:

        show checkmark,
        set variable to 1,
        store variable data to cookie,
        open URL/file.

        I also have the slide entry executing multiple actions:

        retrieve variable,
        if variable is 1, show checkmark, else hide checkmark.

        From what I can tell, the javascript functions do not execute in that scenario.  The cookie is never written.  I added a button as a test that was assigned the “store” function only, and it worked and wrote the cookie, but I need for it to happen at the same time the clickbox is activated with no other buttons to press.  And furthermore, doing that worked for storing the cookie, but when the slide reloads, it doesn’t seem to read the cookie, or if 

        Any thoughts on this?  I feel as though I am going about it the correct way, and the logic all seems sound, but it is not working correctly.

        • http://twitter.com/CaptivatePro CaptivateDev.com

          @Jeremy Tart:  We’ve already corresponded, but want to let those who may be reading the blog know.  If you’re using a conditional advanced action to set a variable using JS (the retrieve cookie function also sets a Cp variable), then use that same retrieved variable for a condition, you’ll run into a timing issue.  The advanced action’s condition will run before the JS can set the variable when it reads the cookie value even though you have set the advanced action to execute the JS first.  Why?  When Flash executes JS, it does it asynchronously… meaning, it will happen on it’s own time line independently of flash.  The demo download example file does not have this problem because it sets and checks for the variable/cookie all in JS.  In Jeremy’s case he was reading a cookie value and displaying an image based on that value all in the same conditional advanced action with multiple steps.  
          The Solution is simple.  Break out the conditional advanced action steps into 2 separate advanced actions.  One that checks / reads the cookie (thus setting your Cp variable), and one that does some kind of action based on the new value of that variable.  In his case, we just added a 0.1 second slide at the beginning of his course that read the cookie (thus setting his Cp variable) on slide entry… then on the following slide entry action, performed an action based on the newly set variable… like displaying a completed check mark.  

  • Mharshaw12

    I downloaded the project files, opened the 5.0 version, hit F12 to run the web preview and it seems like it’s now storing/retrieving the variable for me. The JS file has been updated as well. Did I miss something?

    Thanks,
    Moe 

    • http://twitter.com/CaptivatePro CaptivateDev.com

      Hi Moe… not sure.  What was the original problem?

      • Mharshaw12

        I’m trying to test the original files so that I can familiarize myself with the functionality and it’s not working. Even after I enter a name and hit the “retrieve Variable” button, it’s not displaying. And it still doesn’t display after I hit the “Refresh Page” button.

        • http://twitter.com/CaptivatePro CaptivateDev.com

          Sounds like the cookie is not getting set.  Make sure you’re viewing/publishing to a web server and viewing in a web browser.  This is the only way to accurately test.  Also, I use Chrome’s built in developer tools to see what cookies are being set.  The Chrome console (and even FireFox’s FireBug extension) give a clear visual picture of what’s happening behind the scenes with the cookies.  I typically publish to my local web server to do the testing.

          • Mharshaw12

            Thanks! I’ll continue testing and post back once I’ve figured out what was going on.

  • Alistar

    Hi Jim, a great post with some very useful ideas.

    I was wondering if there was a way to store multiple Captivate variables in a single cookie, or store mulitple variables in multiple cookies.

    I have tried separating mulitple variables with | in the script, with no luck, and also tried having the advanced actions create a cookie for each variable, but that method seems to prevent retrieving of the variables/cookies. It would be great to be able to use your idea with multiple variables.

    Thanks

    Alistar

    • http://twitter.com/CaptivatePro CaptivateDev.com

      @Alistar:  This would be a good case to use 
      setCookie() and getCookie() directly, so you can store / retrieve whatever you want in that string.

  • Julian

    This is a great tip! Thanks for putting this together. I am having a bit of a problem with executing a javascript on entering a slide. When I have On Enter set to either Execute JavaScript or Execute Advanced Action that contains the action Execute Javascript, the project pauses and you have to click the Play button in the PlayBar/Progress Bar to start it again.

    I have a “menu” type project that opens other separate projects by opening the URL for their respective publish projects. Each piece returns to the main menu when the piece concludes.Once a piece is viewed there is an image that is un-hidden on the main menu.I am trying to set a variable in cookie to remember the state of the menu page so that all the images aren’t reset to hidden every time it is reloaded.

    Any help you can offer is appreciated.

    • Julian

      I made it work using the getCookie() function on a 0.1 sec intro slide as suggested, but I’m still curious to know why the JavaScript would be pausing the slide OnEntry.
      Thanks!

      • http://twitter.com/CaptivatePro CaptivateDev.com

        @bb3c2fd122f0cb7bf5a584c96172b80c:disqus :  I have not seen that pausing behavior before.  Maybe you can do a rdcmndResume = 1 in the JS to move the course forward after execution.

  • Areeya_cc

    Hello Jim:
    I try you nice demo on web. Work great!
    But when I download your project and run on web, error pop up Unable to download unspecified error. Would u mind to enlighten me for this issue?

  • Johan Vader

    It’s a nice way to store something in a cookie, using javascript (instead of flash) and the example works fine with captivate 5.5. In Captivate 6 it looks as if the function that is used to retrieve the input from captivate: ”cpEIGetValue” only returns “Undefined”.

    Any idea how to make it work for Captivate 6? 

    • http://twitter.com/CaptivatePro CaptivateDev.com

      @Johan Vader:  To make cpEIGetValue work for Cp 6, preface the variable you want to retrieve with  m_VarHandle.  So if I had a Captivate User variable called v_Name1, you could retrieve this like this:  document.Captivate.cpEIGetValue(“m_VarHandle.v_Name1″);

  • The Dude abides….

    Does this method work the same in 6.0/6.1? I can’t seem to make it happen. I tried copying just the modified lower section of standard.js to the one in the Captivate template folder and it seemed to break the publish. Hmmm.

    • http://twitter.com/CaptivatePro CaptivateDev.com

      @825f34870b943a42a20eb91cbff7eda5:disqus : No it does not work with 6.0 or 6.x. Adobe changed the JavaScript API. You can read about that here: http://captivatedev.com/2012/07/01/adobe-captivate-6-the-javascript-api/

      • The Dude abides…

        Ahhh of course…. I just saw the post below. Thank you so much, great work man!

        • The Dude abides….

          Ok, I have been working all day to resolve cookies within my captivate 6 project and keep running into dead-ends. JS Console says Can’t find variable: dataStore. dataStore is the name I ave the cookie. Does this need to be defined within standard.js? Thanks for any help that any one is willing to provide.

          -tDa

          • http://twitter.com/CaptivatePro CaptivateDev.com

            If you know your audience is going to be using semi-modern browsers, you may want to look at LocalStorage instead of cookies. They’re a lot easier to use.

          • TDA

            Sounds great, are there any examples of LocalStorage being used in this application?

          • http://twitter.com/CaptivatePro CaptivateDev.com

            @TDA Here’s how to use localStorage. I have not done a blog post on how to use it in Captivate, but it should be fairly easy to get/set Captivate variables using localStorage:

            http://coding.smashingmagazine.com/2010/10/11/local-storage-and-how-to-use-it/