I have tables which use DataTables Server Side processing to show on my website. I want to be able to 'Export All' and have all rows be exported, not just those rows being displayed. There are 60000+ rows and 65+ columns, so it must be done with server side processing.
I have tried a few things, but so far nothing has worked.
I have tried this:
{ extend: 'excel',
text: 'Export Current Page',
exportOptions: {
modifier: {
page: 'current'
}
},
customize: function (xlsx)
{
var sheet = xlsx.xl.worksheets['sheet1.xml'];
$('row:first c', sheet).attr('s', '7');
}
}
Which only exported the rows that were showing on the page.
I've tried this:
{
text: 'Export All to Excel',
action: function (e, dt, button, config)
{
dt.one('preXhr', function (e, s, data)
{
data.length = -1;
}).one('draw', function (e, settings, json, xhr)
{
var excelButtonConfig = $.fn.DataTable.ext.buttons.excelHtml5;
var addOptions = { exportOptions: { 'columns': ':all'} };
$.extend(true, excelButtonConfig, addOptions);
excelButtonConfig.action(e, dt, button, excelButtonConfig);
}).draw();
}
}
This sends the whole table's data to the screen instead of using the pagination and sending the whole data set to an excel file.
I've searched around on Google and here in SO, but have not found a solution that works.
I should also mention that I want to Export All based on the current filters set on the table. So that the end user will get an Export of only those rows that they are searching for. They typically limit it to 30k - 40k rows, still with the 65+ columns. I don't (yet) allow to remove/hide columns.
EDIT/UPDATE
Here's a secondary consideration: If I can't Export All from a response from the server, can I build the Excel file on the server? My servers don't have Excel installed and I will still want my end user to get the file. I'm sure that I'd have to find a way to get Excel onto my servers, but how would I transfer any created files to the end user and would that even be any faster than just sending a response with the whole dataset and creating the Excel file on the user's computer?
EDIT
It was recommended that I try jquery's $.ajax() to get this to work. If someone could give me an idea of how to do that I'll try that for a third button.
I can already pull all the data, with the same filters and sorting that are added by the user, and do that with a button. The second attempt above does that but sends it to the screen. I have PHPExcel and a file that can create an Excel sheet. How would I take what I get in that second button and send it to the other file to create the Excel sheet? I thought that using jquery's $.ajax() might work, I just don't know how to get it to. I do know that I'll have to use $_POST since the data could be too big to use $_GET to send the data to the PHPExcel file.
I can already export to a CSV, but I need to export with some formatting, which CSV does not have. That's why I'm going to the trouble of use PHPExcel.
EDIT III
I am trying this, though it's not yet working:
{
text: 'Export all to Excel II',
action: function (e, dt, button, config)
{
dt.one('preXhr', function (e, s, data)
{
data.length = -1;
}).one('export', function (e, settings, json, xhr)
{
var excelButtonConfig = $.fn.DataTable.ext.buttons.excelHtml5;
var addOptions = { exportOptions: { 'columns': ':all'} };
$.extend(true, excelButtonConfig, addOptions);
excelButtonConfig.action(e, dt, button, excelButtonConfig);
})
}
}
EDIT 4
Hopefully the last edit.
I know that I have to do three things to make this work:
Get current Sorting and Filtering
Get dataset with length set to -1
Send this to PHPExcel file for processing and creation of Excel file
I can create a button like this:
{
text: 'Export all Data to Excel',
action:
}
I just don't know what the action needs to be.
My second attempt above pulls the whole dataset that I need, but sends it to the screen instead of to my PHPExcel file (ExportAllToExcel.php).
I have been trying to figure this out and haven't gotten very far. I've been told that I need to use $.ajax() to do this, I've been told that I don't need to use that. I have tried with and without and have not been able to get anywhere.
I have also tried using this to no effect:
$.fn.dataTable.ext.buttons.export =
{
className: 'buttons-alert',
"text": "Export All Test",
action: function (e, dt, node, config)
{
var SearchData = dt.search();
var OrderData = dt.order();
alert("Test Data for Searching: " + SearchData);
alert("Test Data for Ordering: " + OrderData);
}
};
First add the follwoing code in DataTable
"dom": 'Blfrtip',
"buttons": [
{
"extend": 'excel',
"text": '<button class="btn"><i class="fa fa-file-excel-o" style="color: green;"></i> Excel</button>',
"titleAttr": 'Excel',
"action": newexportaction
},
],
Then add this function inside $(document).ready() function
function newexportaction(e, dt, button, config) {
var self = this;
var oldStart = dt.settings()[0]._iDisplayStart;
dt.one('preXhr', function (e, s, data) {
// Just this once, load all data from the server...
data.start = 0;
data.length = 2147483647;
dt.one('preDraw', function (e, settings) {
// Call the original action function
if (button[0].className.indexOf('buttons-copy') >= 0) {
$.fn.dataTable.ext.buttons.copyHtml5.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-excel') >= 0) {
$.fn.dataTable.ext.buttons.excelHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.excelHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.excelFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-csv') >= 0) {
$.fn.dataTable.ext.buttons.csvHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.csvHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.csvFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-pdf') >= 0) {
$.fn.dataTable.ext.buttons.pdfHtml5.available(dt, config) ?
$.fn.dataTable.ext.buttons.pdfHtml5.action.call(self, e, dt, button, config) :
$.fn.dataTable.ext.buttons.pdfFlash.action.call(self, e, dt, button, config);
} else if (button[0].className.indexOf('buttons-print') >= 0) {
$.fn.dataTable.ext.buttons.print.action(e, dt, button, config);
}
dt.one('preXhr', function (e, s, data) {
// DataTables thinks the first item displayed is index 0, but we're not drawing that.
// Set the property to what it was before exporting.
settings._iDisplayStart = oldStart;
data.start = oldStart;
});
// Reload the grid with the original page. Otherwise, API functions like table.cell(this) don't work properly.
setTimeout(dt.ajax.reload, 0);
// Prevent rendering of the full data to the DOM
return false;
});
});
// Requery the server with the new one-time export settings
dt.ajax.reload();
}
I have this working, mostly. It is now timing out, but that's a separate issue due to data size not to this working. For small datasets, it works perfectly.
This is how I create the button (it's the export button that I'm using here):
"buttons": [{
extend: 'collection',
text: 'Selection',
buttons: ['selectAll', 'selectNone']
}, {
extend: 'collection',
text: 'Export',
buttons: ['export', 'excel', 'csv', 'pdf', { extend: 'excel',
text: 'Export Current Page',
exportOptions: {
modifier: {
page: 'current'
}
},
customize: function (xlsx)
{
var sheet = xlsx.xl.worksheets['sheet1.xml'];
$('row:first c', sheet).attr('s', '7');
}
}]
}
]
This is the initialization of the button created above:
$.fn.dataTable.ext.buttons.export =
{
className: 'buttons-alert',
id: 'ExportButton',
text: "Export All Test III",
action: function (e, dt, node, config)
{
var SearchData = dt.rows({ filter: 'applied' }).data();
var SearchData1 = dt.search();
console.log(SearchData);
var OrderData = dt.order();
console.log(SearchData1);
var NumCol = SearchData[0].length;
var NumRow = SearchData.length;
var SearchData2 = [];
for (j = 0; j < NumRow; j++)
{
var NewSearchData = SearchData[j];
for (i = 0; i < NewSearchData.length; i++)
{
NewSearchData[i] = NewSearchData[i].replace("<div class='Scrollable'>", "");
NewSearchData[i] = NewSearchData[i].replace("</div>", "");
}
SearchData2.push([NewSearchData]);
}
for (i = 0; i < SearchData2.length; i++)
{
for (j = 0; j < SearchData2[i].length; j++)
{
SearchData2[i][j] = SearchData2[i][j].join('::');
}
}
SearchData2 = SearchData2.join("%%");
window.location.href = './ServerSide.php?ExportToExcel=Yes';
}
};
And here is the part of the ServerSide.php file that gets the data and sends it to the server for processing:
require('FilterSort.class.php');
if (isset($_GET['ExportToExcel']) && $_GET['ExportToExcel'] == 'Yes')
{
$request = #unserialize($_COOKIE['KeepPost']);
$DataReturn = json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader));
require './ExportAllToExcel.php';
}
else
{
echo json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader));
}
This is how I set the cookie that I use to keep the search and sort criteria:
if(isset($_POST['draw']))
{
$KeepPost = $_POST;
$KeepPost['length'] = -1;
$PostKept = serialize($KeepPost);
setcookie("KeepPost",$PostKept,time() + (60*60*24*7));
}
All this combined sends the correct criteria to FilterSort.class.php which should process the criteria and return the dataset to ExportAllToExcell.php which then creates the Excel file. Right now I'm sending it huge reports and it times out, though.
UPDATE
I have slightly changed the way that I do this:
Here is the new set of buttons:
"buttons": [{
extend: 'collection',
text: 'Export',
buttons: ['export', { extend: 'csv',
text: 'Export All To CSV', //Export all to CSV file
action: function (e, dt, node, config)
{
window.location.href = './ServerSide.php?ExportToCSV=Yes';
}
}, 'csv', 'pdf', { extend: 'excel',
text: 'Export Current Page', //Export to Excel only the current page and highlight the first row as headers
exportOptions: {
modifier: {
page: 'current'
}
},
customize: function (xlsx)
{
var sheet = xlsx.xl.worksheets['sheet1.xml'];
$('row:first c', sheet).attr('s', '7');
}
}]
}
]
Here is how I create the Export All to Excel button:
$.fn.dataTable.ext.buttons.export =
{
className: 'buttons-alert', //Adds the "Export all to Excel" button
id: 'ExportButton',
text: "Export All To Excel",
action: function (e, dt, node, config)
{
window.location.href = './ServerSide.php?ExportToExcel=Yes';
}
};
These now send the data to the same ServerSide.php file that I was using before:
require('FilterSort.class.php');
if (isset($_GET['ExportToExcel']) && $_GET['ExportToExcel'] == 'Yes')
{
include 'Helper/LogReport.php';
$GetSQL = "Select Value from PostKept where UserName = '" .$_COOKIE['UserName']. "'";
$KeepResult = $conn->query($GetSQL);
$KeepResults = $KeepResult->fetchALL(PDO::FETCH_ASSOC);
$request = unserialize($KeepResults[0]['Value']);
$DataReturn = json_encode(FilterSort::complex($request,$sqlConnect,$table,$primaryKey,$ColumnHeader,1));
require './ExportAllToExcel.php';
I have also changed the way that I keep the query, I have it now also keeping the Table Name and UserName like this:
include 'DBConn.php';
$KeepPost = $_POST; //POST holds all the data for the search
$KeepPost['length'] = -1; //-1 means pulling the whole table
$PostKept = serialize($KeepPost); //This takes the array of data and turns it into a string for storage in SQL
$SQLCheck = "select distinct UserName from PostKept"; //Gets all the distinct Usernames of users that have used the Report Dashboard.
$sth = $conn->query($SQLCheck);
$CheckedUser = $sth->fetchALL(PDO::FETCH_ASSOC);
foreach($CheckedUser as $User)
{
foreach($User as $Index => $Who)
{
$FoundUsers[] = $Who; //Taking all the found users and placing them into a simpler array for searching later
}
}
if(isset($_COOKIE['UserName']) && in_array($_COOKIE['UserName'],$FoundUsers)) //If the user already has an entry update it with new information
{
$TSQL = "UPDATE PostKept set Value = '" .$PostKept. "', TableName = '" .$TableName. "' where UserName = '" .$_COOKIE['UserName']. "'";
}
else
{
if(isset($_COOKIE['UserName'])) //If this is a new user
{
$TSQL = "INSERT into PostKept(Value, TableName, UserName) select '" .$PostKept. "','" .$TableName. "','" .$_COOKIE['UserName']. "'";
}
else //If this is on the Prod site and the User info is not yet kept
{
$TSQL = "INSERT into PostKept(Value, TableName) select '" .$PostKept. "','" .$TableName. "'";
}
}
$sth = $conn->prepare($TSQL);
$sth->execute();
This is now what all combines to send the data to the ExportAllToExcel.php file that I have and then it in turn creates the file.
I just ran into this and came up with an alternate solution.
In the DataTable options, add this:
"lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
This will allow user to select all rows and will send -1 to server in 'length' query string parameter. At server side, you need to handle negative number and allow to return all rows when -1 is received.
This would display all rows in table and will export all of them.
I understand that this may not be suitable for 50-60K rows but for a smaller dataset, this can work without implementing any additional code at server and client side both.
in buttons:
action: function (e, dt, node, config) {
var formData = 'yourfilters';
formData.begin = '0';
formData.length = 'yourTotalSize';
$http({
url: 'yourURL',
method: 'POST',
data: JSON.stringify(formData)
}).then(function (ajaxReturnedData) {
dt.rows.add(ajaxReturnedData.data).draw();
$.fn.dataTable.ext.buttons.excelHtml5.action.call(this, e, dt, node, config);
});}
I'm trying to show data from visitors inside a map created using jvectormap plugin.
This is driving me crazy, i can not load the data through ajax, if i put the data manually it works.
So far i have this:
map.php
$datos = array();
$link->set_charset("utf8");
$sql = $link->query("SELECT SUM(ID) as visitors, state FROM visitors WHERE state != '' GROUP BY state");
while($row = $sql->fetch_row()){
$ss = $link->query("SELECT * FROM states WHERE state = '".$row[1]."'");
$rr = $ss->fetch_row();
$datos[] = array("ccode" => $rr[2], "visits" => $row[0]);
}
$data = array("countries" => $datos);
echo json_encode($data,JSON_NUMERIC_CHECK);
This returns the following data:
{"countries":[{"ccode":"VE-A","visits":81},{"ccode":"VE-L","visits":24}]}
Now the function to load the map:
function cargaMapa(){
//jvectormap data
$.post("ajax/map.php",{},function(mapa){
var dataC = eval(mapa);
//var dataC = {"countries":[{"ccode":"VE-A","visits":81},{"ccode":"VE-L","visits":24}]};
var countryData = [];
//for each country, set the code and value
$.each(dataC.countries, function() {
countryData[this.ccode] = this.visits;
console.log("Estado: "+this.ccode+" Visitas: "+this.visits);
});
//World map by jvectormap
$('#world-map').vectorMap({
map: 've_mill_en',
backgroundColor: "#fff",
regionStyle: {
initial: {
fill: '#e4e4e4',
"fill-opacity": 1,
stroke: 'none',
"stroke-width": 0,
"stroke-opacity": 1
}
},
series: {
regions: [{
values: countryData,
scale: ["#3c8dbc", "#2D79A6"], //['#3E5E6B', '#A6BAC2'],
normalizeFunction: 'polynomial'
}]
},
onRegionLabelShow: function(e, el, code) {
//search through dataC to find the selected country by it's code
var country = $.grep(dataC.countries, function(obj, index) {
return obj.ccode == code;
})[0]; //snag the first one
//only if selected country was found in dataC
if (country != undefined) {
el.html(el.html() + ': ' + country.ccode + country.visits + ' visitas');
}
}
});
});
}
As you can see in the function i have the var dataC, if i load in there the array coming from map.php it gives me Uncaught SyntaxError: Unexpected token : but if copy and paste the result of map.php into the var dataC it works pretty good.
How can i solve this?
I appreciate any help
Thanks
I figured it out, just changed $.post for $.getJSON and the magic began
It's becoming a nightmare for me solving this problem. I am developing an app using phonegap. I have used highcharts in it for Graphs. The graph is coming properly but not the tooltip in the graph. Please check the code below, I need this code to be able to show the tooltip with proper data. There has to be a loop of the following code and it has to be for every user or series in the graph. So I have ran a for loop in PHP and saved it in a variable and got the whole output of the loop using AJAX in a JSON format.
When I use the variable in the Javascript code in which I have saved the AJAX output, it just doesn't do anything but if I alert than it alerts the exact code which I want to make tooltip work. I have tried eval() also but no benefit. Any help or guidance will be much appreciated.
Loop Code
$toolTip = '';
for($i=0;$i<$teamControllerW->total_user;$i++){
$toolTip .= "var chart = $('#team_containerWF').highcharts();";
$toolTip .= "var figures".$i." = [".join($teamControllerW->new_yAxesData1[$i], ",") ."]; ";
$toolTip .= "var fatVals".$i." = [". join($teamControllerW->fatVal[$i], ',') ."]; ";
$toolTip .= "var weightVals".$i." = [". join($teamControllerW->weightVal[$i], ',') ."]; ";
$toolTip .= "var result_playing_dates = [". join($teamControllerW->new_playing_dates_data[$i], ',') ."]; ";
$toolTip .= "
$.each(figures".$i.", function (j, figure".$i.") {
var curDanger = (figure".$i."[0] - danger[0][0]) * delta + danger[0][1];
var play_date = false;
for (var k = 0; k < result_playing_dates.length ; k ++ ) {
if (figure".$i."[0] == result_playing_dates[k]) {
play_date = true;
break;
}
}
";
$toolTip .= "if (figure".$i."[1] > curDanger) {
if (play_date) {
if (chart.series[".$i."].data[j] && chart.series[".$i."].data[j].graphic) {
chart.series[".$i."].data[j].graphic.attr({ fill: '#a31515' });
chart.series[".$i."].data[j].update({
fatVal : fatVals".$i."[j],
weightVal : weightVals".$i."[j],
marker:{
fillColor: '#a31515',
radius: 6,
states: {
hover: {
fillColor: '#a31515',
lineColor: '#a31515',
radius: 10
}
}
}
});
}
}
else {
if (chart.series[".$i."].data[j] && chart.series[".$i."].data[j].graphic) {
chart.series[".$i."].data[j].graphic.attr({ fill: 'red' });
chart.series[".$i."].data[j].update({
fatVal : fatVals".$i."[j],
weightVal : weightVals".$i."[j],
marker:{
fillColor: 'red',
states: {
hover: {
fillColor: 'red',
lineColor: 'red'
}
}
}
});
}
}
}else{
if (play_date) {
if (chart.series[".$i."].data[j] && chart.series[".$i."].data[j].graphic) {
chart.series[".$i."].data[j].graphic.attr({ fill: '#02491a' });
chart.series[".$i."].data[j].update({
fatVal : fatVals".$i."[j],
weightVal : weightVals".$i."[j],
marker:{
fillColor: '#02491a',
radius: 6,
states: {
hover: {
fillColor: '#02491a',
lineColor: '#02491a',
radius: 10
}
}
}
});
}
}
else {
if (chart.series[".$i."].data[j] && chart.series[".$i."].data[j].graphic) {
chart.series[".$i."].data[j].graphic.attr({ fill: 'green' });
chart.series[".$i."].data[j].update({
fatVal : fatVals".$i."[j],
weightVal : weightVals".$i."[j],
marker:{
fillColor: 'green',
states: {
hover: {
fillColor: 'green',
lineColor: 'green'
}
}
}
});
}
}
}
});
";
}//end for
I'm calling the data like this
var teamweighinLMgameAction = window.localStorage.getItem("teamweighinLMgameAction");
AGWeigh = JSON.parse(teamweighinLMgameAction);
var toolTip = AGWeigh.toolTip;
alert(toolTip);//On alert it comes fine
if(data_avail=='yes') { //check if data available
var danger = myDangerLine,
deltaX = danger[1][0] - danger[0][0],
deltaY = danger[1][1] - danger[0][1],
delta = deltaY / deltaX;
alert("In: "+toolTip);//the data also alerts fine here
toolTip; //This is the place where I need the loop output but it nothing comes up
}
Ok this sounds like "Loop Code" being result of an AJAX call has passed js code "var chart = $('#team_containerWF').highcharts();..."!! However, this will never get executed by the main page. An AJAX result being passed should ideally be JSON/XML and then only contain name value pairs of data. Such that your main code being viewed would:
validate those name value pairs
execute its own code to render the graph based on those name value pairs
Therefore, my recommendation is try to structure it that firstly Main page handles the logic for display in Javascript, and AJAX pages in PHP handle the logic for pulling data and not display.
Also you could provide us with a bit more detail on the structure of your project. Label your code e.g. index.php getChartPlayingDates.php?
Can't find the solution to this anywhere and I really hope it's possible.
I'm writing a Jira gadget and I have a configuration screen with 2 fields. One is the quickfind project picker; you type and it finds projects and you click the one you want.
The second field is Component. You can select the component of the project that you wish to filter by. However the components are different for each project so the Component field is populated with a AJAX call specified in the gadget in the "args" section of the "config" part.
Only problem is that this AJAX only gets called when the gadget is first loaded; i.e.: before a project is selected so the result is always "Select A Project".
I need a way to rerun this AJAX call on the event of the selected project being changed.
Is this possible? Or is there an alternative solution? I've tried timers to check for changes but there were a few problems there also; mainly that I couldn't access/alter the Component drop-box field. The gadget would just refuse to load.
Update: Below is the Javascript for the gadget. As you can see I added a refreshComponents() Javascript method which can retrieve the Components given a project ID however I have no way to attach this to the appropriate event. Also I can't seem to directly alter any components on the the page with the likes of jQuery or ordinary JS
<div id="chart_div" style="overflow: auto;"></div>
<script type="text/javascript">
var gadget = this;
google.load('visualization', '1.0', {'packages':['corechart']});
var oldProject = "initiated";
var globalGadget;
function timedComponentUpdate()
{
//alert(globalGadget.getPref("projectId"));
//setTimeout("timedComponentUpdate()",3000);
}
function refreshComponents(idString)
{
//refetch components
var url = "__ATLASSIAN_BASE_URL__/rest/severity-gadget/1.0/severity-issues/getComponents.json";
url += "?projectId=" + idString;
alert(url);
var xmlhttp;
if (window.XMLHttpRequest)
xmlhttp=new XMLHttpRequest();
else
{
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4)
{
//document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
alert(xmlhttp.responseText);
}
}
xmlhttp.open("GET",url,true);
xmlhttp.send();
}
function drawChart(args, bugtype, comp) {
//setup for whether were getting opened or closed
var axisTitle;
var compTitle;
var chart;
if(bugtype == "Bug")
axisTitle = "Bug";
else
axisTitle = "Issue";
if(comp == "All")
compTitle = "";
else
compTitle = " - Component: " + comp;
var wVar = gadgets.window.getViewportDimensions().width-20;
var hVar = wVar/3;
var hVar = hVar*2;
// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Issues');
data.addColumn('number', 'Trivial');
data.addColumn('number', 'Minor');
data.addColumn('number', 'Major');
data.addColumn('number', 'Critical');
data.addColumn('number', 'Blocker');
AJS.$(args.weeks).each(function() {
data.addRow(["Week "+this.number,
parseInt(this.issues[0]),
parseInt(this.issues[1]),
parseInt(this.issues[2]),
parseInt(this.issues[3]),
parseInt(this.issues[4])
]);
});
var options = {'title':'Weekly '+axisTitle+' Backlog' + compTitle,
'width':wVar,
'height':hVar,
axisFontSize:4,
isStacked:true,
fontName: '"Arial"'
};
chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
var gadget = AJS.Gadget(
{
baseUrl: "__ATLASSIAN_BASE_URL__",
useOauth: "/rest/gadget/1.0/currentUser",
config: {
descriptor: function(args)
{
document.getElementById("chart_div").innerHTML = "";
var gadget = this;
var projectPicker = AJS.gadget.fields.projectOrFilterPicker(gadget, "projectId", args.projectOptions);
//bh
oldProject = this.getPref("projectId");
//refreshComponents(this.getPref("projectId"));
return {
theme : function()
{
if (gadgets.window.getViewportDimensions().width < 450)
{
return "gdt top-label";
}
else
{
return "gdt";
}
}(),
fields: [
AJS.gadget.fields.nowConfigured(),
projectPicker,
AJS.gadget.fields.days(gadget, "weeksPrevious"),
{
userpref: "issueType",
label: "Issue Type:",
description:"Choose which issue type you would like",
type: "select",
selected: this.getPref("issueType"),
options:[
{
label:"Any",
value:"Any"
},
{
label:"Bug",
value:"Bug"
}
]
},
{
userpref: "component",
label: "Component:",
description:"Choose which issue type you would like",
type: "select",
selected: this.getPref("component"),
options:args.components
}
]
};
},
args: function()
{
return [
{
key: "components",
ajaxOptions: function() {
var ajaxProject = this.getPref("projectId");
if(ajaxProject == "")
ajaxProject = "null";
return {
url: "/rest/severity-gadget/1.0/severity-issues/getComponents.json",
data:
{
projectId : ajaxProject
}
}
}
}
];
}()
},
view: {
onResizeReload: true,
onResizeAdjustHeight: true,
template: function(args) {
var gadget = this;
gadget.getView().empty();
drawChart(args.issueData, this.getPref("issueType"), this.getPref("component"));
gadget.resize();
},
args: [{
key: "issueData",
ajaxOptions: function() {
return {
url: "/rest/severity-gadget/1.0/severity-issues.json",
data: {
projectId : gadgets.util.unescapeString(this.getPref("projectId")),
weeksPrevious: this.getPref("weeksPrevious"),
issueType: this.getPref("issueType"),
component: this.getPref("component"),
backlog: true
}
};
}
}]
}
}
);
</script>
I think you'll need to turn your component field into a Callback Builder.
Inside the callback function you'll need to do a few things:
retrieve the options via an AJAX request
render the dropdown
attach an event handler to refresh the list when a particular event occurs
Your new component field might look something like this... I've assumed you've got jQuery available for brevity.
{
userpref: "component",
label: "Component",
id: "component_field_id"
description: "Choose which issue type you would like",
type: "callbackBuilder",
callback: function(parentDiv){
function renderOptions(options){
// Remove elements from the parentDiv and replace them
// with new elements based on the options param
// You can use gadget.getPref('component') to ensure you
// mark the right option as selected
}
function getOptions(){
$.ajax({
url: "__ATLASSIAN_BASE_URL__/rest/severity-gadget/1.0/severity-issues/getComponents.json",
data: {
// You might be able to get hold of the selected value
// from the gadget object instead of like this
projectId: $("#filter_projectOrFilterId_id").val()
}
}).done(renderOptions);
}
// Retrieve and render options on gadget load
getOptions();
// Retrieve and render options on an event
$(parentDiv).on("update-options", getOptions);
}
}
Additionally, you'll need to trigger an event when the project select field value changes. Somewhere else in your JS code (not inside the gadget definition) you'll need to put code like this, but you'll need to confirm the CSS selector for the project/filter selector:
$(document).on("change", "#filter_projectOrFilterId_id", function(){
$("#component_field_id").trigger("update-options");
});
I've not tested this but that's how I'd attempt to achieve what you're asking for.