Highcharts pie charts served from AJAX call - ajax

I am trying different ways of rendering json data from mysql/php to Highcharts. So far I've been successful rendering bar charts using this approach but for some reason, I have not been able to render data in a pie chart.
One js file handles the AJAX call:
$(function () {
var select_program = program_type_php;
var select_year = '2016';
console.log ('pie_chart'+program_type_php);
$.ajax({
url: 'model/job_group_pie_chart.php',
data: {user: 2, select_program:select_program, select_year:select_year},
type: 'GET',
async: true,
dataType: "json",
success: function (year_2016) {
pie_chart_2016(year_2016);
console.log('data 2016 job groups'+year_2016);
}
});
Upon success, I call a function in another js file (in this example, 'pie_chart_2016' and pass it the data object.
Here's the other js file responsible for rendering the data into a Highchart:
function pie_chart_2016 (year_2016) {
console.log('year_2016'+year_2016);
$('#pie-chart1').highcharts({
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: ''
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
},
showInLegend: true
},
series: year_2016
}
});
};
I have checked, and I do get valid json from my php file:
[{name:"Group1",y:829},{name:"Group2",y:9247},{name:"Group3",y:71}]
These are raw counts (829, 9247, 71) but when I was able to get a pie chart to render by inputting values manually, Highcharts calculated the percentages for me - nice!
I've also set up enough console.logs to know that my functions are being called, and that my data object is being processed.
Still, all I get is a blank panel, and 'highcharts.com' in the lower left hand corner, so the html is working too.
The approach I'm using works really well with bar charts, so I am stumped!
Thanks for any help you can provide.

Thanks to Rahul, I moved 'series:' outside of plotOptions, and added these lines. I should have caught this sooner, that pie charts needs the 'data' property while bar charts have that included in their JSON array. Appears to be working well for now. Thanks again Rahul!
series: [{
name: 'Job Group',
colorByPoint: true,
data: year_2016
}]

Related

How to remove previous data when executing AJAX request multiple times

I have an issue with ajax calling. It works correct except one thing, when I try to get data with the same option more than one times returns the new response but also still return the data of the previous response.
I think that there is something that I've missed.
ajax script
$('#search').on('click', function () {
var date = $("#date").val();
$.ajax({
type: 'GET',
url: '{{Route("dashboard.status")}}',
data: {
date: date
},
dataType: "JSon",
success: function(response){
console.log(response.manager_hourlog);
// Employee report script
var colors = ["#1abc9c", "#2ecc71", "#3498db", "#9b59b6", "#34495e", "#16a085", "#27ae60", "#2980b9", "#8e44ad", "#2c3e50", "#f1c40f", "#e67e22", "#e74c3c", "#ecf0f1", "#95a5a6", "#f39c12", "#d35400", "#c0392b", "#bdc3c7", "#7f8c8d"];
#if ($auth->user_type != 1)
// manager report script
var managerchartbar = {
labels: response.manager_projects,
datasets:
[{
label: response.users,
backgroundColor: colors[Math.floor(Math.random() * colors.length)],
data: response.totals
},]
};
var ctx = document.getElementById('manager').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: managerchartbar,
options: {
title: {
display: true,
text: 'Project Report chart'
},
tooltips: {
mode: 'index',
intersect: false
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
}
});
#endif
},
error: function(xhr){
console.log(xhr.responseText);
}});
});
});
</script>
You should change your method to POST for json request/response API, will be more secure and avoid laravel cache view it.
type: 'POST',
Try to change method to POST (do same for your api server and route).
If not work, please show your laravel API code.
you should set cache property to false or append "_={timestamp}" to the GET parameter
so add cache to your request:
cache:false
or append timestamp to your url:
url: '{{Route("dashboard.status")}}'+'_='+ + new Date().getTime(),

jqGrid applying sort from known values not working

I have a jqGrid and want to apply user's sort values after it loads. These values are saved and retrieved in jquery cookies. I am storing data in cookies because user will go to another url and come back which initiates page load and they want to be in same spot they left.
I have a loadPreferences function being called within loadComplete.
See code snippet below(I left several jqrid properties out to keep posting short).
// Set up the jquery grid
$("#jqGridTable").jqGrid(
{
// Ajax related configurations
url: jqDataUrl,
datatype: "json",
mtype: "GET",
autowidth: true,
// Configure the columns
colModel: columnModels,
// Grid total width and height
height: "100%",
// customize jqgrid post init
gridComplete: function()
{
CRef.updateJqGridPagerIcons("jqGridTable");
},
// Default sorting
sortname: "LastName",
sortorder: "asc",
sorttype: "text",
sortable: true,
jsonReader:
{
root: "rows",
page: "page",
total: "total",
records: "records",
repeatitems: false,
userdata: "userdata"
},
loadComplete: function (data)
{
if (boolPreferencesLoaded == false)//page level variable
{
boolPreferencesLoaded = loadPreferences(this);
$("#jqGridTable").trigger("reloadGrid");
}
isGridSorting(this, false);
}
...the rest of grid properties...
and in the function call(which is located in another js file), I have...
function loadPreferences(gridId)
{
if (typeof $.cookie("sortCol") !== "undefined")
{
$(gridId).jqGrid("sortGrid", $.cookie("sortCol"), true, $.cookie("sortOrd"));
}
return true;
}
function isGridSorting(gridId, sorting)
{
$.cookie("sortCol", $(gridId).jqGrid('getGridParam', 'sortname'));
$.cookie("sortOrd", $(gridId).jqGrid('getGridParam', 'sortorder'));
$(gridId).jqGrid('setGridParam', { postData: { isSorting: sorting } });
}
My problem is when I go to apply them on page load(with jqGrid specified above), it does not exactly work. The icon moves to correct column and the arrow is pointing in correct direction, but the data in column does not sort.
I know there are a lot of posts dealing with similar issues, but not able to get solutions to work. What I am trying to do seems to easy, but it's driving me nuts. If you respond, please make comment easy to understand. Thank you.

How to pre-load an array via ajax and use it for select2?

My general problem is that I want to have a Javascript variable which I then use with select2, to prepare the options for a select multiple. I have a fairly large array (7000 objects) and just want to store that once in a variable rather than constantly polling the server with search terms. Here is what I got.
The HTML is simply:
<input type="hidden" id="group_a" multiple="multiple" placeholder="Select at least two treatments">
Now, when I write the variable directly everything works as expected:
var treatments = [{id: 1, text: "you"}, {id: 2, text: "me"}];
$("#group_a").select2({
data: treatments,
minimumInputLength: 1,
multiple: true,
closeOnSelect: false,
width: "660px"
});
However, when I use ajax to load the array things get weird. My code to do that:
$.ajax({
url: '/funny/url',
}).done(function(data) {
treatments = data.choices;
});
I tend to get the following error unless I use the debugger to step through the code, then it works as expected. So could this somehow be a timing issue?
uncaught exception: query function not defined for Select2 group_a
My complete javascript looks like below and I've also prepared a fiddle which shows the same error.
$(document).ready(function() {
var treatments;
$.ajax({
url: '/funny/url',
}).done(function(data) {
treatments = data.choices;
});
$("#group_a").select2({
data: treatments,
minimumInputLength: 1,
multiple: true,
closeOnSelect: false,
width: "960px"
});
});
The ajax call is asynchronous, so at the time you are instrumenting the Select2 control, treatments is still undefined.
You could do the following:
$(document).ready(function() {
$.ajax({
url: '/funny/url',
}).done(function(data) {
$("#group_a").select2({
data: data.choices,
minimumInputLength: 1,
multiple: true,
closeOnSelect: false,
width: "960px"
});
});
});
jsfiddle
Better yet though, I would do the following.
Initially set treatments to an empty array, and use a function for the data option so if treatments is changed, the changes will be picked up by the Select2 control. That way, you can instrument the Select2 control right away, and then update treatments with the data returned by the ajax call. Additionally, you could initially disable the Select2 control, and then enable it when the ajax call returns.
$(document).ready(function() {
var treatments = [];
$.ajax({
url: '/funny/url',
}).done(function(data) {
treatments = data.choices;
$("#group_a").select2('enable', true);
});
$("#group_a").select2({
data: function() { return { results: treatments }; },
minimumInputLength: 1,
multiple: true,
closeOnSelect: false,
width: "960px"
}).select2('enable', false);
});
jsfiddle
The third option would be to keep your original code, but make the ajax call synchronous. I recommend not doing that though. When you make an ajax call synchronous, you lock up the entire browser.
Here is my solution. Thanks to #John S for the initial approach, but I couldn't get the select2 formatter to parse my array. Select2 box would tell me 'no results found.' I ended up running a for loop through my array and writing out the :id, :text hashes.
Starting with my json ajax call is an array of string 'terms':
// localhost:3000/search/typeahead_terms_all.json
[
"Super Term",
"cool term",
"killer term",
"awesome term",
"try term",
"param term",
"try name",
"Academic Year",
"grade average",
"Hello Term",
"Academic Calendar",
"kinda cool term",
"My Term",
]
Then the javascript:
$(document).ready(function() {
var term_names_array = [];
$.ajax({
url: '/search/typeahead_terms_all',
}).done(function(data) {
// Here I iterate through my array of strings and write out the hash select2 needs
for (index = 0; index < data.length; ++index) {
term_names_array.push({ id: index, text: data[index] });
}
$('.report_term_input').select2('enable', true);
});
$('.report_term_input').select2({
dataType: 'json',
data: term_names_array,
multiple: true,
width: "500px"
});
});

SharePoint 2013 and Kendo Grid cross domain call issues

I am having a small issue that I just can't seem to figure out. I am trying to make a simple SharePoint 2013 demo app that gets a few fields from a list on the parent site and binds to a kendo grid.
Due to the new nature of SP2013, app's get created in their own local site which makes these calls cross domain. When I make the call, no data is pulled back. When I compare a working call vs the call being made by the app, I can see that a cookie is not present in the call that is failing (which is why no data is being pulled back). If anyone could offer any hints or suggestions on things to try, I would appreciate it.
The List I am trying to call is called KendoGridList and I am trying to pull back the first and last name and bind to the grid. Below is my code:
EDIT: After looking into the code a little deeper, it looks like a cookie is not getting passed in the call to the service. If I take the cookie from a normal rest call to the service which works and add it to the composer in fiddler the call goes through and returns data.
$(document).ready(function () {
$("#grid").empty();
var siteUrl = "site url placed here";
var url = siteUrl + "/_vti_bin/Listdata.svc/KendoGridList/?$select=FirstName,LastName";
grid = $("#grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: {
url: url,
dataType: "json",
beforeSend: function (xhr) {
xhr.setRequestHeader("Accept", "application/json;odata=verbose");
}
}
},
schema: {
type: "json",
model: {
fields: {
FirstName: "FirstName",
LastName: "LastName"
}
}
},
pageSize: 10,
serverPaging: true,
serverFiltering: true,
serverSorting: true,
change: function (e) { // data load completed for grid
},
},
filterable: false,
sortable: true,
pageable: true,
scrollable: false,
//groupable: true,
columns: [{
field: "FirstName",
title: "First Name",
width: 50
}, {
field: "LastName",
title: "Last Name",
width: 50
}
]
});
});
I've also tried using:
read: {
url: url,
type: "GET",
dataType: "json",
contentType: "application/json;odata=verbose",
headers: {
"accept": "application/json;odata=verbose"
}
},
If you are using a provider-hosted app you should try using the SP cross-domain library. I think your best bet is to retrieve the data using the library and then bind the resulting info to the grid.
http://blogs.msdn.com/b/officeapps/archive/2012/11/29/solving-cross-domain-problems-in-apps-for-sharepoint.aspx

HighCharts - How to create dynamic chart that exports EVERYTHING

I'm trying to export a dynamically generated chart and I've noticed that some things don't get exported. For example, my chart has PlotBands which are dynamic depending on the data being displayed.
As I built my chart, I followed the standard code layout of all the great HighChart examples where I generated the chart immediately on the document load. Then later in my code, I use an Ajax call to load the data and modify things like titles, plot bands, custom text, etc.
The problem is that anything modified on the chart after the initial chart load won't be exported to images or PDFs. My PlotBands were added during the Ajax call. They couldn't be included in the chart object that was built on document.load(). So they were conveniently ignored by HighCharts.
In my chart, I want to show energy usage during a 24-hour period at different sites. The user can choose different days and different sites. The Plot Bands needed to highlight the operating hours and each site has different operating hours which are loaded with the data. Also, the chart title shows the site name and the subtitle shows the square footage.
Additionally, my code draws some custom text on the bottom of the graph using the HighCharts renderer text() command.
My code for the barely-functioning export looks something like this:
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: "ChartContainer",
type: "line",
title: { text: null },
subtitle: { text: null }
}
}
});
function UpdateChart() {
$.ajax({
url: "/my/url.php",
success: function(json) {
chart.addSeries(json[1]);
chart.addSeries(json[2]);
chart.setTitle(json[0].title, json[0].subtitle);
chart.xAxis[0].addPlotBand({ color: "#FCFFB9", from: json[0].OpenInterval, to: json[0].CloseInterval, label: { text: "Operating Hours", verticalAlign: "bottom", y: -5, style: { fontSize: "8pt", color: "gray" } } });
chart.renderer.text("Custom Text", 50, 100);
}
});
}
Unfortunately, the title, the plot bands and the "custom text" won't appear if the user exports the chart.
yes - its possible and highcharts support things you mentioned here's sample code http://jsfiddle.net/vijaykumarkagne/9c2vqq7q/ of dynamic highchart using json data of file hosted in google drive.
$.getJSON("https://b943d995d961c8938d74bf398f8748e2b34864c6.googledrive.com/host/0B_i_hw1oG1HeaU9nMWxfTnJZd1k/data.json",{format:"json"},function(result){
chart = new Highcharts.Chart({
chart: {
zoomType: 'x',
type: 'line',
renderTo: 'container'
},
title: {
text: ' '
},
subtitle: {
text: 'Click and drag in the plot area to zoom in',
x: -20
},
xAxis: {
type: 'datetime',
title: {
text: ' '
}
},
yAxis: {
title: {
text: ' '
}
},
series:[{
name: 'Tokyo',
data: result
}]
});
});
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://b943d995d961c8938d74bf398f8748e2b34864c6.googledrive.com/host/0B_i_hw1oG1HeaU9nMWxfTnJZd1k/dataEmp.json"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/drilldown.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<body>
<div id="container"></div>
</body>
(answering my own question here)
The key is to re-arrange how you build your chart.
Don't generate the chart on the document.load(). Generate it in the success() function of the ajax call.
First, check if the chart already exists and destroy() it. If your code allows the users to dynamically change settings, that will cause a new ajax call to execute which will need to update the graph. The chart needs to be destroyed before being re-built.
Now build a new chart from scratch. But, now you already have the data you need from the ajax call so you can build it from scratch with the correct information. HighCharts will only export data that was included the first time the chart was created. So all custom data needs to be included here. If you need to change something on the graph, destroy it and rebuild it using the custom data.
function UpdateChart() {
$.ajax({
url: "/my/url.php",
success: function(json) {
// If the chart exists, destroy it
if (chart) chart.destroy();
// Create the chart
chart = new Highcharts.Chart({
chart: {
renderTo: "ChartContainer",
type: "line",
events: {
load: function(event) {
this.renderer.text("Custom Text", 50, 100);
}
},
title: { text: json[0].title },
subtitle: { text: json[0].sqft }
},
plotBands: {
color: "#FCFFB9",
from: json[0].OpenInterval,
to: json[0].CloseInterval,
label: {
text: "Store Hours", verticalAlign: "bottom", y: -5, style: { fontSize: "8pt", color: "gray" }
}
}
};
// Add two data series to the chart
chart.addSeries(json[1]);
chart.addSeries(json[2]);
// Set title and sub-title
chart.setTitle(json[0].title, json[0].subtitle);
}
});
}
Now, the chart will show all the custom things you've added. Notice that the custom text written to the chart using the renderer.text() command are added in the chart.load() event. For some reason, it only works here.
Remember the key: HighCharts will only export data that was included the first time the chart was created. This will save you a lot of headaches.

Resources