Skip to content

Refresh All Data Sources

Keshia Rose edited this page Aug 20, 2020 · 21 revisions

API: Extensions API
Difficulty: ⚫⚫⚪⚪
Requirements: Text editor, Web hosting or local web server

This mini project will show you how to set up an extension that will let an end user refresh all data sources used in a dashboard at the same time. Extensions are a way to embed web applications into Tableau dashboards that allow you to extend the features or Tableau and integrate with other applications.

Set up your environment

In this mini project, we will be utilizing Glitch as our text editor and hosting service.

  1. Create your own copy of the starter project by remixing it.
  2. To keep your project and make all your projects easy to find later click Sign In to create an account.
  3. Click on the Show link at the top then click In New Window to go to your project page.
  4. Copy the URL on that page, it should look something like: https://three-lamb.glitch.me/.
  5. Close the live preview page and go back to the editor. Click on MyAwesomeExtension.trex to open it. Change YOUR URL HERE to the URL you copied in the last step.
  6. Download the MyAwesomeExtension.trex file by editing and pasting the below link into your browser window. <YOUR URL HERE>/MyAwesomeExtension.trex. The file should download into your downloads folder.

Start Desktop in debug mode

Windows
  1. Exit Tableau if it is already running on your computer.
  2. Open a Command Prompt window.
  3. Start Tableau using the following command. Replace with the version of Tableau you are using (for example, Tableau 2019.1).
"C:\Program Files\Tableau\Tableau <version>\bin\tableau.exe" --remote-debugging-port=8696
Mac
  1. Open a Terminal window.
  2. Start Tableau using the following command. Replace with the version of Tableau you are using (for example,2019.1.app).
open /Applications/Tableau\ Desktop\ <version>.app --args --remote-debugging-port=8696

Test your extension

  1. Download the sample Orders data set,People data set and RefreshAll.twb. Open the workbook in the Desktop instance you just opened with the debugger. (File > Open, not just double click)
  2. Drag and drop a new Extension object (bottom left pane) to the bottom of your dashboard.
  3. Allow the extension to run.
  4. Confirm that you see "This is an extension!".
  5. Go back to Glitch and change "This is an extension!" to a different phrase.
  6. Reload your extension and make sure you see your phrase in Tableau.

Start coding!

  1. In Glitch, go to your index.html file and before the </head> line, add a line to reference the Tableau Extensions API library:
<script src="https://cdn.jsdelivr.net/gh/tableau/extensions-api/lib/tableau.extensions.1.latest.js"></script>
  1. Next, go to the script.js file (which is already referenced in index.html) and add the following to initialize your extension:
tableau.extensions.initializeAsynch().then(() => {
  console.log('I have been initialized!!')
});

Wait! Let's use the debugger

  1. In your browser, go to the debugging homepage (http://localhost:8696).
    Note: This will not work if you are using Chrome version 80 or higher. It will also not work if you are on Tableau Desktop 2018.3 or lower. If either of these is the case, please follow the instructions here to download the Chromium browser for debugging.
  2. Click on your extension in the browser (should be named "My Awesome Extension").
  3. If it's not already selected, click the Console tab at the top to open the console.
  4. Notice we're getting an error saying Uncaught TypeError: tableau.extensions.initializeAsynch is not a function at script.js:1. Looks like there is a typo in our call to initialize. Remove the 'h' from the end of the function call initializeAsynch -> initializeAsync in script.js.
tableau.extensions.initializeAsync().then(() => {
  console.log('I have been initialized!!')
});
  1. Reload the extension in Tableau by clicking the down arrow on the extension zone and selecting Reload from the menu.
  2. In your browser with the debugger, go to http://localhost:8696 again and click on My Awesome Extension. (Note you must reload the page, hitting back alone will not reset the console)
  3. You should now see the message "I have been initialized!!" in the console. Use this console to test and debug your extension as you work.

Add the refresh button

Our goal in this section will be to refresh all data sources when a button is clicked.

  1. Before we begin, familiarize yourself with the Extensions API Reference. We will be calling refreshAsync() on a data source.
  2. In your index.html file between the <body> tags, remove "This is an extension!" and add a button with an onClick event like this: <button type="button" onclick="refresh()">Refresh</button>. We'll create the refresh() function in our script.js file later.
  3. RefreshAsync() is a method that runs on a data source but first, to get data sources we must get a worksheet. In order to get the worksheets, first, we have to get the dashboard. Add a new custom function after initialization with the following line to grab the dashboard:
function refreshAllDataSources () { 
    let dashboard = tableau.extensions.dashboardContent.dashboard; 
} 

Note: this is the function that we linked the button to earlier 2. Then from there, we can now iterate throw the worksheets on the dashboard to get the data sources.

dashboard.worksheets.forEach(function (worksheet) {                  

}); 

Note: _Try console logging dashboard to see its structure. 

  1. At this point your script.js file should look something like this:
tableau.extensions.initializeAsync().then(() => { 
  console.log('I have been initialized!!') 
}); 

function refreshAllDataSources() { 
    let dashboard = tableau.extensions.dashboardContent.dashboard; 
    dashboard.worksheets.forEach(function (worksheet) { 
           
    }); 
} 
  1. Next, we need to get the data sources we want to refresh using getDataSourcesAsync(). This function is returning promises. We want then to add all the different promises to an array. But first, we need to initialize this array first dataSourceFetchPromises and after push the promises.
let dataSourceFetchPromises = []; 
dashboard.worksheets.forEach(function (worksheet) { 
                dataSourceFetchPromises.push(worksheet.getDataSourcesAsync()); 
}); 
  1. Your script.js file should now look like this:
tableau.extensions.initializeAsync().then(() => { 
  console.log('I have been initialized!!') 
}); 

function refreshAllDataSources () { 
    let dashboard = tableau.extensions.dashboardContent.dashboard; 
    let dataSourceFetchPromises = []; 
    dashboard.worksheets.forEach(function (worksheet) { 
           dataSourceFetchPromises.push(worksheet.getDataSourcesAsync()); 
    }); 
} 
  1. getDataSourcesAsync(). is an asynchronous function which means code that is written right after will not wait for the data to return. To make sure we are waiting until the call is finished before moving on, we need to wrap up dataSourceFetchPromises inside of promise.all(). And for the next piece of code, we will add it inside of the then() method. To get a much better explanation of asynchronous calls and promises check out  one, of these.
  2. Now that we have the data sources in our array, we can iterate through them and run refreshAsync() on it! Add the following after you get the data source: 
Promise.all(dataSourceFetchPromises).then(function (fetchResults) { 
                fetchResults.forEach(function (dataSourcesForWorksheet) { 
                    dataSourcesForWorksheet.forEach(function (dataSource) { 
                          dataSource.refreshAsync(); 
                    }); 
                }); 
}); 
  1. Now our code needs to keep track of our progress. If two worksheets are connected to the same data source, we want this data source to be refreshed only once. For that, we need first to initialize a new object.
const dashboard = tableau.extensions.dashboardContent.dashboard; 
let dataSourceFetchPromises = []; 
let dashboardDataSources = {};

This new object is going to store all the data sources that we are refreshing. We also need to add an if statement to be sure we are not refreshing a data source multiple times.

  1. Your final script.js file should look like this:
tableau.extensions.initializeAsync().then(() => { 
  console.log('I have been initialized!!') 
}); 

function refreshAllDataSources() {  
            const dashboard = tableau.extensions.dashboardContent.dashboard; 
            let dataSourceFetchPromises = []; 
            let dashboardDataSources = {};
            dashboard.worksheets.forEach(function (worksheet) { 
                dataSourceFetchPromises.push(worksheet.getDataSourcesAsync()); 
            }); 
            Promise.all(dataSourceFetchPromises).then(function (fetchResults) { 
                fetchResults.forEach(function (dataSourcesForWorksheet) { 
                    dataSourcesForWorksheet.forEach(function (dataSource) { 
                        if (!dashboardDataSources[dataSource.id]) { 
                            dashboardDataSources[dataSource.id] = dataSource; 
                            dataSource.refreshAsync(); 
                        } 
                    }); 
                }); 
            }); 
} 
  1. Test your extension by editing the two excel files with a new row of data. Then click on the button to see your dashboard update!

Challenge exercises

Now that you know the basics of refreshing data sources, try implementing the following bonus challenges.

  1. Add separate unique buttons to refresh each data source found.
  2. Refresh the data source every 30 seconds, or allow for the user to set an interval.