In this short tutorial I will go thru the basic steps of creating a project that uses Tableau JavaScript API. My intent is to show non-developers how the typical implementation workflow looks like. Obviously, there are multiple ways to achieve the same goals but the way of implementing new web applications is pretty much the same. Let me share my flow and show how I usually setup a development environment, embed a view and capture parameter and event changes. I will use my chess game as an example.
I have two distinct toolchains for web development:
- The first and preferred is the combination of clojure, clojurescript, leiningen, boot, ring, reagent from cursive IDE relying mostly on REPL based development workflow. Even if this is my favourite one this has a relatively steep learning curve, therefore it’s probably not the best to start with.
- In contrast using yeoman, grunt/gulp, bower, jade, underscore and coffeescript from any convenient editor (like vim) is an easy ride. All components are easy to learn.
So let’s pick the second one and start embedding our tableau workbook.
Installing prerequisites
First of all, you need a command line javascript interpreter application namely node.js. This is the same V8 javascript runtime that is running in Google Chrome browsers. You can download and install it from https://nodejs.org/en/download/ for your platform.
Now you should create a folder for your project (I will name my folder as tableau-chess-tutorial ) then go into it. Next step is to install our scaffolding tool (generates our project’s skeleton from templates) called yeoman. Yeoman comes with great number of generators, it has building blocks for web data connectors as well. To install simply use the node package manager (npm) and type:
1 |
npm install -g yo |
The -g option stands for global so it will be accessible from all node project. Now we can install one of the yeoman templates from http://yeoman.io/generators/. I’ll pick generator-simpleapp. It has a simple grunt based build system with coffeescript and sass support discussed in details later. To install the generator simply type:
1 |
npm install -g generator-simpleapp |
Generating the application
Everything is ready to generate our new application. For this, simple type yo then select the simpleapp template and give a nice name to our application.
Version control
After the generation we can initialise a new git repository (it’s a version control system what you can download from here) with the command git init . Later we can use git to share our source codes with others on github or automatically deploy the generated application to github.io project pages hosting server.
Hello world!
After the generation you can add the famous text hello world to the file app/index.html between the <body></body> tags. To see the results we should build our “application” with the command grunt . It will compile the sources, copy the resources to a distribution directory, start a web server and point your default browser to the results. All the magic with a single command.
I think it was a little too much for once. But no worries, let me show it in practice (you can copy paste from the video):
It’s less scary now I guess.
File structure and build process
Just quickly summarise what happened. We just jumped into a preconfigured build environment with sample files. Our application lives under the app directory. When we run the grunt command it will execute a mini web server and watch for file changes in the application directory. If a file changes it will reload the javascript files directly in our browser, thus, depending on the change you don’t even have to reload the page what you’re developing.
Register project on github
To share our code and generated application the best way is to register a project on github. Everyone can register a free user account on github and create unlimited open source projects. To create a new repository simply fill project name:

Create project on git
Fill project settings in package.json
We can add metadata to our project like description, license and github repository url. To add these information simply edit package.json file and fill accordingly.
1 2 3 4 5 6 7 8 9 10 11 |
{ "name": "tableau-chess-tutorial", "version": "0.0.0", "description": "Tableau Server JS API Tutorial", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/tfoldi/tableau-chess-tutorial.git" }, "dependencies": {}, [..] |
Add files to github
To add our files to our local git repository we should first add, then commit the files. This can be done with the following commands:
1 2 3 4 5 6 7 8 |
# First add the current directory and all subdirectories with its contents git add . # Commit all changes git commit -a # Register our remote github repository git remote add origin https://github.com/tfoldi/tableau-chess-tutorial.git # Push our local changes to github git push origin master |
Deploy to github.io
When you finished you can simply issue grunt deploy which will send the compiled application to github pages. The files will be available under https://<github-username>.github.io/<project-name>/ URL. In my case this will be https://tfoldi.github.io/tableau-chess-tutorial/

Now hello world is really for the whole world
And now the whole process again from our terminal’s perspective:
In fact, within five minutes we just built a basic application, set up version control and uploaded the results to github.io. I think it’s not that bad. But we need more than just a hello world, so keep reading.
Embedding our viz
CoffeeScript? I thought it should be in JavaScript
JavaScript is a great language but it has its weaknesses. According to coffeescript.org CoffeeScript is:
CoffeeScript is a little language that compiles into JavaScript. Underneath that awkward Java-esque patina, JavaScript has always had a gorgeous heart. CoffeeScript is an attempt to expose the good parts of JavaScript in a simple way.
Practically CoffeeScript is javascript but with different syntax. It’s similar to python, instead of special characters like semicolon you open and close the blocks with indentation. If you check the basic tableau report embedding javascript snippet on the API tutorial site, the embedding code is:
1 2 3 4 5 6 7 8 9 10 11 12 |
function initViz() { var containerDiv = document.getElementById("vizContainer"), url = "http://public.tableau.com/views/RegionalSampleWorkbook/Storms", options = { hideTabs: true, onFirstInteractive: function () { console.log("Run this code when the viz has finished loading."); } }; var viz = new tableau.Viz(containerDiv, url, options); } |
The same code in CoffeeScript (converted with js2.coffee) is way shorter and descriptive.
1 2 3 4 5 6 7 8 |
initViz = -> containerDiv = document.getElementById('vizContainer') url = 'http://public.tableau.com/views/RegionalSampleWorkbook/Storms' options = hideTabs: true onFirstInteractive: -> console.log 'Run this code when the viz has finished loading.' viz = new tableau.Viz(containerDiv, url, options) |
It’s more clean and readable, especially when we work with more complex code. If you have doubt about the syntax just open js2.coffee and check how it would look like in javascript or coffee, respectively.
Our grunt based build system takes care of the coffee to javascript compilation. The only thing we have to do is to start our web server with simple grunt command and start writing our code. Whenever we change our coffee files they immediately get compiled.
1 2 3 4 5 6 |
>> File "app/javascripts/application.coffee" changed. >> File "app/index.html" changed. Running "coffee:dist" (coffee) task Done, without errors. Completed in 3.753s at Sun Jul 24 2016 20:20:23 GMT+0200 (CEST) - Waiting... |
Basic embed of our viz
If you check the API Samples library the Basic Embed is easy, you need only a few things:
- Create an identifiable div element (practically a div element with and id attribute)
- An initalizer function that loads the visualization
- A method that calls the initalizer function
- Optionally a function/callback which is called when the viz is initialized
Looks easy, so finally let’s write some code:
You can find the complete code tree here. Have a look in app/index.html and app/javascripts/application.coffee files.
Capture events: parameters and mark selections
For my chess game the interaction’s key was to capture user actions like field selection and parameter selection. Handling events with the Tableau Javascript API is fairly easy if not trivial. Let’s capture all parameter changes and mark selections and show them in a div container.
The easiest way for that is to use console-log-div module. We just need to include its javascript file where we’d like to see our console logs. We can leverage our frontend javascript package manager (bower) for the installation.
To install frontend packages we need to add the package name into
bower.json file. In addition to console-log-div I will add underscore.js as well to be able to use more functional programming like style later this tutorial.
Please note that I added js:build tags around console-log-div. This tells our build system that we need this file to be uglyfied before the deploy meaning that compress it as much as possible. After deploying our current state to github.io we should see something like this:

Console div shows our console.log messages
Now lets register our event handlers and print out their data. The official samples are pretty good, however, you need to start with the asynchronous classes in the documentation to understand the concept of promises. TL;DR: when you call an async function you should pass a callback to then function which will be called after the asynchronous operation finished.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# Main CoffeeScript File initViz = -> containerDiv = document.getElementById('vizContainer') url = 'https://public.tableau.com/views/Chess_3/Board' options = hideTabs: true onFirstInteractive: -> viz.addEventListener( tableau.TableauEventName.MARKS_SELECTION, (marksEvent) -> marksEvent.getMarksAsync().then marksSelected) viz.addEventListener( tableau.TableauEventName.PARAMETER_VALUE_CHANGE, (parameterEvent) -> parameterEvent.getParameterAsync().then parameterSelected) console.log 'Run this code when the viz has finished loading.' window.viz = new tableau.Viz(containerDiv, url, options) |
Registering an event handler is easy, just call addEventListener with two parameters: first is the event type (full list of types is here), second is a callback which called when the event occurs. This is where we face with the asynchronicity in first time. But no issues, we just need to call the then function and pass our callback executed after we received the marks or parameters.
Handling the marks selected events is also easy. Tableau passes and array of array of pairs representing each mark selection with their object=value details. Using map-reduce we can easily print out their values to the console:
24 25 26 27 28 29 30 31 32 33 |
parameterSelected = (parameter) -> console.log "Paremeter #{parameter.getName()} = #{parameter.getCurrentValue().value}" marksSelected = (marks) -> _.each marks, (mark, idx) -> console.log _.reduce mark.getPairs(), (memo, pair) -> "#{memo} #{pair.fieldName}=#{pair.formattedValue}," "Marker: #{idx}, Values:" |
Please note that I don’t use variables or for cycles – they are evil and should be avoided when possible.
After I did my last grunt deploy my results can be viewed here: https://tfoldi.github.io/tableau-chess-tutorial/ along with the source codes here: https://github.com/tfoldi/tableau-chess-tutorial/blob/master/app/javascripts/application.coffee
It was easy, we know the user’s interaction – the only thing remained is to integrate with our chess framework.
Summary
This post’s goal was to give a detailed overview how a typical development process looks like including scaffolding, personalisation, git setup, deployment and actual iterative coding. If you made it here you’re surely one of the chosen fews. If you have question don’t forget to ask it in the comment section.
- Tableau Extensions Addons Introduction: Synchronized Scrollbars - December 2, 2019
- Tableau External Services API: Adding Haskell Expressions as Calculations - November 20, 2019
- Scaling out Tableau Extracts – Building a distributed, multi-node MPP Hyper Cluster - August 11, 2019