Skip to content

Instantly share code, notes, and snippets.

@faustomorales
Created March 6, 2016 05:03
Show Gist options
  • Save faustomorales/08909d702f6fe452541e to your computer and use it in GitHub Desktop.
Save faustomorales/08909d702f6fe452541e to your computer and use it in GitHub Desktop.
Angular directive to embed Tableau dashboards
/* Using this directive is as easy as 1, 2, 3.
1. Grab the Tableau API JavaScript library as well as this module.
a. <script src="path/to/tableau-2.0.0.min.js"></script>
b. <script src="path/to/angular-tableau.js"></script>
2. Import the module into your app by adding 'angular-tableau' to your dependencies.
3. Use the directive like this:
<tableau-viz height="'500px'"
url="path/to/tableau-dashboard"
filters={'field1':['item1', 'item2'], 'dateField':{'min':startDate, 'max':endDate}}">
</tableau-viz>
a. You can add 'cover' to the directive to prevent the user from interacting with the dashboard.
b. You can add 'showTabs' and 'showToolbar' to show tabs or the toolbar (hidden by default)
c. Remember to add width or height, as appropriate for your layout (use the width and height
attributes on the directive). Not sure which one you need? Try the height setting first.
*/
angular.module("angular-tableau",[])
.value('tableau',tableau)
.directive('tableauViz', ['$q','$interval','tableau',function($q,$interval,tableauApi) {
return {
restrict: 'E',
template:'<div></div><div style="position: absolute; top:0; height:100%; width:100%; opacity: 0;"></div>',
scope: {
url: '=',
height: '=',
width: '=',
filters: '='
},
link: function(scope,element,attrs) {
// Just some housekeeping since the browser won't know how to style this element
element.css('display', 'block');
element.css('position', 'relative');
// Set target for viz
var vizTarget = element[0].children[0];
var viz;
// Block user input if cover is specified
if(!('cover' in attrs)) {
var cover = angular.element(element[0].children[1]);
cover.css('display','none');
}
// We need to have a URL to do anything
if(!scope.url) {
console.log("Error: No URL was specified for Tableau Viz");
return;
}
// Create the dashboard
function createViz() {
viz = new tableauApi.Viz(vizTarget, scope.url, {
'height': scope.height ? scope.height : '100%',
'width': scope.width ? scope.width : '100%',
'hideTabs': 'showTabs' in attrs ? false : true,
'hideToolbar': 'showToolbar' in attrs ? false : true,
'onFirstInteractive': function() {
applyFilters();
scope.$watch('filters', function(newValue, oldValue) {
applyFilters();
}, true);
}
});
}
createViz();
// We need to rebuild the dashboard periodically to accommodate session timeouts. This is pretty hacky though. :/
var stop = $interval(function rebuild() {
viz.dispose();
createViz();
}, 300000)
// Destroy the dashboard and interval timers upon destroying directive.
scope.$on('$destroy', function() {
if (viz) viz.dispose();
if (angular.isDefined(stop)) {
$interval.cancel(stop);
stop = undefined;
}
});
// Define a function to apply filters to dashboard
function applyFilters() {
var dash = viz.getWorkbook().getActiveSheet();
var filtersArr = Object.keys(scope.filters);
for (var i=0; i<filtersArr.length; i++) {
var filterValue = scope.filters[filtersArr[i]];
// If it's a dashboard, we need to filter each sheet individually.
if(dash.getSheetType() === 'dashboard') {
var sheets = dash.getWorksheets();
for(var j=0; j<sheets.length; j++) {
applyFilterToSheet(sheets[j], filtersArr[i], filterValue)
}
}
if(dash.getSheetType() === 'worksheet') {
applyFilterToSheet(dash, filtersArr[i], filterValue)
}
}
}
// Define a function to apply filters to individual sheet
function applyFilterToSheet(sheet, key, filter) {
if(filter.min && filter.max) {
// Deal with JavaScript quirk on date objects.
var postIncrementDate = angular.copy(filter.max);
postIncrementDate.setDate(postIncrementDate.getDate() + 1);
sheet.applyRangeFilterAsync(key, {
min: filter.min,
max: postIncrementDate
});
}
else {
sheet.applyFilterAsync(key, filter, tableau.FilterUpdateType.REPLACE)
}
}
}
};
}])
@Phota80
Copy link

Phota80 commented Apr 1, 2016

Hi,
I am new to tableau & Angularjs. Got error Failed to load resource tableau-2.0.3.js.

Could you let me know the path where i can download that file. Also please send your html file & angularjs controller file code.

thank you

@yobre
Copy link

yobre commented Apr 5, 2016

hi Fausto,
good job with this directive!

One question: What is the value of
.value('tableau', tableau)

Where you've valorize the Value?

Thanks

@bruizar
Copy link

bruizar commented Jun 6, 2016

Thanks for the work. I tried to get this to work with a random public viz but I'm getting an error:

Error: [$parse:syntax] Syntax Error: Token ':' is an unexpected token at column 6 of the expression [https://public.tableau.com/views/USMassShooting2013-2015TrendsPerState/Story1?:embed=y] starting at [://public.tableau.com/views/USMassShooting2013-2015TrendsPerState/Story1?:embed=y].

<tableau-viz height="'500px'"
      url="https://public.tableau.com/views/USMassShooting2013-2015TrendsPerState/Story1?:embed=y"
      filters={'field1':['item1', 'item2'], 'dateField':{'min':startDate, 'max':endDate}}">
</tableau-viz>

Any idea how to solve this?

@jbernard1
Copy link

<tableau-viz height="'500px'" url="https://public.tableau.com/views/USMassShooting2013-2015TrendsPerState/Story1?:embed=y" filters={'field1':['item1', 'item2'], 'dateField':{'min':startDate, 'max':endDate}}"> </tableau-viz>

Change to

<tableau-viz height="'500px'" url="https://public.tableau.com/views/USMassShooting2013-2015TrendsPerState/Story1?:embed=y" filters="{'field1':['item1', 'item2'], 'dateField':{'min':startDate, 'max':endDate}}"> </tableau-viz>

you were missing a initial double quotes for your filters property

@pallaviMN
Copy link

Can any one please share any codepen or JSFiddle for angularjs + tableau

@hmartos
Copy link

hmartos commented Sep 7, 2016

Here there is a JSFiddle with an example

https://jsfiddle.net/hmartos/rdrgvn3r/

@raghubala
Copy link

Is there an angular 2 version of it?

@alabgold
Copy link

Do you have any suggestions about putting Tableau visualizations on angular cards?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment