Pass data to Javascript function - c#

I am using the following snippet to populate a Google Chart-
<script type="text/javascript">
google.load("visualization", "1", { packages: ["corechart"] });
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Year', 'Sales', 'Expenses'],
['2004', 1000, 400],
['2005', 1170, 460],
['2006', 660, 1120],
['2007', 1030, 540]
]);
var options = {
title: 'Company Performance'
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
This works a treat and creates a line graph as desired.
However I wish to pass data to this function from my code behind -
protected void Page_Load(object sender, EventArgs e)
{
string JsonString = "{'res':[{'category':'A','count':17167},{'category':'B','count':18183},{'category':'C','count':17972},{'category':'D','count':18539}]}";
Jobj = JObject.Parse(JsonString);
// extract values from Json
foreach (var response in Jobj["res"])
{
string category= (string)response["category"];
int count = (int)response["count"];
// put values into format that can be passed to the javascript function
}
}
And then use is like -
function drawChart() {
var data = google.visualization.arrayToDataTable([<%=Data Values%>]);
Where count and category are the X and Y axis values and the 17167,18183 etc are the points on the graph.
However clearly the aforementioned syntax is incorrect, how can I modify the function to accept my Json data?

Since you already have the JSON string, there's no point in parsing it, then re-serializing it. Just inject it directly, and use Javascript to map into the Google Viz format:
function drawChart() {
var json = <%= JsonString %>;
var arr = [ ["Category", "Count"] ];
json.res.forEach(function(item) {
arr.push( [ item.category, item.count ] );
});
console.log(JSON.stringify(arr)); // [["Category","Count"],["A",17167],["B",18183],["C",17972],["D",18539]]
var data = google.visualization.arrayToDataTable(arr);
}
Here is demo of the data-mapping part.

Related

Google chart for asp.net core Razor Pages

I am following this tutorial https://dotnetthoughts.net/integrating-google-charts-in-aspnet-core/ and am stuck trying to load the chart data from the Index.cshtml.cs page via the 'OnGetChartData' ActionResult. I get an 'Failed to load resource: the server responded with a status of 404 ()' exception and the console pointing to Index?handler=OnGetChartData. The problem seems to be in the url specification but I have not managed to figure out the correct string.
Any suggestions are appreciated!
public ActionResult OnGetChartData()
{
var pizza = new[]
{
new {Name = "Mushrooms", Count = 4},
new {Name = "Onions", Count = 1},
new {Name = "Olives", Count = 1},
new {Name = "Zucchini", Count = 1},
new {Name = "Pepperoni", Count = 2}
};
var json = pizza.ToGoogleDataTable()
.NewColumn(new Column(ColumnType.String, "Topping"), x => x.Name)
.NewColumn(new Column(ColumnType.Number, "Slices"), x => x.Count)
.Build()
.GetJson();
return Content(json);
}
Here is the scripts section: drawChart1 works as expected.
#section Scripts
{
// Load the Visualization API and the corechart package
google.charts.load('current', { 'packages': ['corechart'] });
// Set a callback to run for each chart when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(drawChart1);
google.charts.setOnLoadCallback(drawChart2);
// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart1() {
// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'Topping');
data.addColumn('number', 'Slices');
data.addRows([
['Mushrooms', 3],
['Onions', 1],
['Olives', 1],
['Zucchini', 1],
['Pepperoni', 2]
]);
// Set chart options
var options = {
'title': 'How Much Pizza I Ate Last Night',
'width': 400,
'height': 300
};
// Instantiate and draw our chart, passing in some options.
var chart1 = new google.visualization.PieChart(document.getElementById('chart1'));
chart1.draw(data, options);
}
function drawChart2() {
// Create the data table.
var jsonData = $.ajax({
url: "/Index?handler=OnGetChartData",
dataType: "json",
async: true
}).responseText;
var data = new google.visualization.DataTable(jsonData);
// Set chart options
var options = {
'title': 'How Much Pizza I Ate Last Night',
'width': 400,
'height': 300
};
// Instantiate and draw our chart, passing in some options.
var chart2 = new google.visualization.PieChart(document.getElementById('chart2'));
chart2.draw(data, options);
}
</script>
Rewrote the answer, in the first attempt i missed the fact this was razor pages ...
The url should be
url: "/Index?handler=ChartData"
and not
url: "/Index?handler=OnGetChartData"
The OnGet part of the method name just indicates this method is a HTTP Get.
You can even simplify it further by removing the /Index and just use
url: "?handler=ChartData"
I expect your PageModel class to look something like this
public class IndexModel : PageModel {
...
public ActionResult OnGetChartData() {
...
}
}
You can just paste the url directly into the browser to ensure it returns something reasonable

Why is JSON Object for Ajax throwing an error, but json file doesn't?

I try to give a JSON object to display in a google chart.
I can show a google chart when i call in the ajax the json file, but when i try to get the data from codebehind, i get an error.
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string GetData()
{
var chartData = new object[10+ 1];
int j = 0;
for (int i=1; i <= 10; i++)
{
chartData[j] = new object[] { i.ToString(), i*i, i};
j++;
}
//return chartData;
string json = JsonConvert.SerializeObject(chartData);
return json;
}
The Json string i get here is valid according to a json formatter.
"[[\"1\",1,1],[\"2\",4,2],[\"3\",9,3],[\"4\",16,4],[\"5\",25,5],[\"6\",36,6],[\"7\",49,7],[\"8\",64,8],[\"9\",81,9],[\"10\",100,10]]"
So i have string, number, number as an array.
My call looks like this (I have it from https://www.encodedna.com/google-chart/create-line-charts-with-dynamic-json-data-using-google-charts.htm) and this works fine if i use a json file for the data, when i try to use the data from code behind it jumps into the error:
<script>
// Visualization API with the 'corechart' package. url: "data.json",
google.charts.load('visualization', { packages: ['corechart'] });
google.charts.setOnLoadCallback(drawLineChart);
function drawLineChart() {
$.ajax({
url: "Chart.aspx/GetData",
dataType: "json",
type: "GET",
contentType: "application/json; charset=utf-8",
success: function (data) {
var arrSales = [['RejectReason', 'Count', 'Perc. (%)']]; // Define an array and assign columns for the chart.
// Loop through each data and populate the array.
$.each(data, function (index, value) {
arrSales.push([value.RejectReason, value.Count, value.Perc]);
});
// Set chart Options.
var options = {
title: 'Sorting',
curveType: 'function',
legend: { position: 'bottom', textStyle: { color: '#555', fontSize: 14 } } // You can position the legend on 'top' or at the 'bottom'.
};
// Create DataTable and add the array to it.
var figures = google.visualization.arrayToDataTable(arrSales)
// Define the chart type (LineChart) and the container (a DIV in our case).
var chart = new google.visualization.LineChart(document.getElementById('chart'));
chart.draw(figures, options); // Draw the chart with Options.
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('Got an Error');
}
});
}
I want the code behind to be shown in the google chart. Later i want to use extracted and enriched data from a database to be shown, so i will not access it from a json file.
This is wrong JSON data
You should avoid the " and \ from your JSON string
[[1,1,1],[2,4,2],[3,9,3],[4,16,4],[5,25,5],[6,36,6],[7,49,7],[8,64,8],[9,81,9],[10,100,10]]
you can use the copied code from JSON formatter, it is just made for view purposes only. Your JSON file contain correct JSON. i think it is not a human-readable format.

How to format google chart x axis in DateTime format from C#

I'm developing a web site in MVC 5 and I'm using google chart to display some chart for my data. I'm using the line chart for a data which have a value and a date. Something like the follow:
class ChartData
{
public double Value { get; set; }
public DateTime Date { get; set; }
};
In my controller I have a request handler to generate the data for the chart:
public JsonResult GenerateChartData(int id)
{
List<ChartData> list = new List<ChartData>();
// some code to populate the list
return Json(list, JsonRequestBehavior.AllowGet);
}
Everything works fine except that the X axis which should show the date time sequence is formatted in the wrong way. The looks like absolute time not in readable date format.
see the chart output
thanks for any answer
google charts will accept dates in a couple ways,
which depend on how the data table, used to draw the chart, is loaded...
1)
if you're using one of the following methods to load the data table...
addRow(), addRows(), arrayToDataTable()
the date will need to be a javascript date object,
created using the new keyword,
any valid constructor will work
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, date[, hours[, minutes[, seconds[, milliseconds]]]]]);
2)
if using json to load the data table directly...
var data = new google.visualization.DataTable(jsonData);
the following string format can be used...
which needs to be a string value (wrapped in quotes), without the new keyword...
"Date(Year, Month, Day, Hours, Minutes, Seconds, Milliseconds)"
where Month is zero-based
"Date(2017, 4, 16)" // <-- 5/16/2017
This is the way to load the data inside a java script. But in my case the data are generate in json format by a request to the controller. I post the code of my page
#model BDF.RemoteData.Data.TagData
#{
ViewBag.Title = "Chart";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>[[[Grafico]]]</h2>
<input type="hidden" id="idInput" data-value="#ViewBag.id" />
<input type="hidden" id="idSystem" data-value="#ViewBag.system" />
<input type="hidden" id="idStart" data-value="#ViewBag.start" />
<input type="hidden" id="idEnd" data-value="#ViewBag.end" />
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1",
{
packages: ["corechart"]
});
google.setOnLoadCallback(drawChart);
function drawChart()
{
var id = $("#idInput").data("value");
var system = $("#idSystem").data("value");
var start = $("#idStart").data("value");
var end = $("#idEnd").data("value");
$.ajax(
{
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: '#Url.Action("GenerateChartData")',
data:
{
id: id,
system: system,
start: start,
end: end
},
type: "GET",
error: function (xhr, status, error)
{
var err = eval("(" + xhr.responseText + ")");
toastr.error(err.message);
},
beforeSend: function ()
{
},
success: function (data)
{
HistDashboardChart(data);
return false;
},
error: function (xhr, status, error)
{
var err = eval("(" + xhr.responseText + ")");
toastr.error(err.message);
},
complete: function ()
{
}
});
return false;
}
//This function is used to bind the user data to chart
function HistDashboardChart(data)
{
$("#Data_Chart").show();
var dataArray = [
['Date', 'Value']
];
$.each(data, function (i, item)
{
dataArray.push([item.Date, item.Value]);
});
var data = google.visualization.arrayToDataTable(dataArray);
var options = {
legend:
{
position: 'bottom',
textStyle:
{
color: '#f5f5f5'
}
},
colors: ['#34A853', 'ff6600', '#FBBC05'],
backgroundColor: '#454545',
hAxis:
{
title: 'Time',
titleTextStyle:
{
italic: false,
color: '#00BBF1',
fontSize: '20'
},
textStyle:
{
color: '#f5f5f5'
}
},
vAxis:
{
baselineColor: '#f5f5f5',
title: 'Values',
titleTextStyle:
{
color: '#00BBF1',
italic: false,
fontSize: '20'
},
textStyle:
{
color: '#f5f5f5'
},
viewWindow:
{
min: 0,
format: 'long'
}
},
curveType: 'function',
};
var chart = new google.visualization.LineChart(document.getElementById('Data_Chart'));
chart.draw(data, options);
return false;
};
</script>
<div id="Data_Chart" style="width: 100%; height: 500px"> </div>
As you can see the job id done by the request url: '#Url.Action("GenerateChartData")'
Then the returned data are pushed into an array the the code
var dataArray = [
['Date', 'Value']
];
$.each(data, function (i, item)
{
dataArray.push([item.Date, item.Value]);
});
In this case I'm assuming that item.Date is already in a datetime format but maybe I have to format it in a special way.
The output of the console.log(item.Date) is the following:
/Date(1494937128000)/
/Date(1494937133000)/
/Date(1494937138000)/
/Date(1494937143000)/
/Date(1494937148000)/
/Date(1494937153000)/
/Date(1494937158000)/
/Date(1494937163000)/
Which looks strange I think, doesn't it?
Ok I got it. Reading this article made everything clear
How to parse JSON to receive a Date object in JavaScript?
I modified the java script code inside my page in the following way:
var dataArray = [
['Date', 'Value']
];
$.each(jsondata, function (i, item) {
var d = new Date(parseInt(item.Instant.substr(6)));
dataArray.push([d, item.Value]);
});
Now it works perfectly

Knockout ViewModel Update

I am new to Knockout and I am trying to update my ViewModel from an ajax call. This is what I have right now:
LoanDeductions.js
var deductionLine = function (deductionID, deductionName, amount) {
self = this;
self.deductionID = ko.observable(deductionID);
self.deductionName = ko.observable(deductionName);
self.amount = ko.observable(amount);
};
function LoanDeductions(deductions) {
var self = this;
self.loanDeductions = ko.observableArray(ko.utils.arrayMap(deductions, function (deduction) {
return new deductionLine(deduction.deductionID, deduction.deductionName, deduction.amount)
}));
// Operationss
self.removeLine = function (line) { self.loanDeductions.remove(line) };
};
and this is my scripts in my view:
#section scripts
{
<script src="~/Scripts/koModel/LoanDeductions.js"></script>
<script type="text/javascript">
var updateValues = function () {
$.ajax({
'url': '#Url.Action("UpdateDeductionValues","LoanApp")',
'data': { amount: $('.LoanAmount').val() },
'success': function (result) {// update viewmodel scripts here}
});
var viewModel = new LoanDeductions(#Html.Raw(Model.CRefLoansDeductions2.ToJson()));
$(document).ready(function () {
ko.applyBindings(viewModel);
$('.datepicker').datepicker();
$('.LoanAmount').change(function () {
updateValues();
};
});
});
</script>
}
So, in my view, I have a dropdown list with class name "LoanAmount" which when value is changed, it will perform an ajax call, send the selected loanAmount value to the server, recompute the deduction amounts, then the server returns a jsonresult that looks like this:
"[{\"deductionID\":1,\"deductionName\":\"Loan Redemption Fee\",\"amount\":53.10},{\"deductionID\":2,\"deductionName\":\"Document Stamp\",\"amount\":9.00}]"
Now what I wanted to do is use this json data as my new viewModel.
Can anyone show me the way how to do this, please note that I manually mapped my viewmodel and didn't used the ko mapping plugin.
Any help will be greatly appreciated. Thank you, more power!
EDIT (in response to Fabio)
function updateData() {
$.ajax({
url: '#Url.Action("UpdateDeductionValues","LoanApp")',
data: { amount: self.selectedLoanAmount() },
success: function (deductions) {
//load your array with ko.utils.arrayMap
ko.utils.arrayMap(deductions, function (deduction) {
return new deductionLine(deduction.deductionID, deduction.deductionName, deduction.amount)
});
}
});
}
Not sure If I understood your problem, but if you want to change model values outside of the class, you need to do something like this:
$(document).ready(function () {
var viewModel = new LoanDeductions(#Html.Raw(Model.CRefLoansDeductions2.ToJson()));
ko.applyBindings(viewModel);
$('.datepicker').datepicker();
function updateValues() {
//do you ajax call
//update the model using viewModel.loanDeductions(newItens);
};
$('.LoanAmount').change(function () {
updateValues();
};
});
EDIT 1 - Just to show how to use knockout without jquery.change
function LoadDeductions() {
//declare you properties
var self = this;
self.loanAmount = ko.observable('initialvalueofloanamount');
self.loanDeductions = ko.observableArray();
//create a function to update you observablearray
function updateData() {
$.ajax({
url: '#Url.Content('yourActionhere')' or '#Url.Action('a', 'b')',
data: { amount: self.loadAmount() },
success: function (deductions) {
//load your array with ko.utils.arrayMap
}
});
}
//everytime that loanAmount changes, update the array
self.loanAmount.subscribe(function () {
updateData();
});
//update values initializing
updateData();
};
$(function() {
ko.applyBindings(new LoadDeductions());
});
Bind the select in the HTML
<select data-bind="value: loanAmount"></select>
EDIT 2 - To your second problem
function updateData() {
$.ajax({
url: '/LoanApp/UpdateDeductionValues', //try to write the url like this
data: { amount: self.selectedLoanAmount() },
success: function (deductions) {
//load your array with ko.utils.arrayMap
self.loanDeductions(ko.utils.arrayMap(deductions, function (deduction) {
return new deductionLine(deduction.deductionID, deduction.deductionName, deduction.amount)
}));
}
});
}
Your success handler should look like this.
function(result){
self.loanDeductions(result);
}
Unless you are trying to append in which case it would be
self.loanDeductions(self.loanDeductions().concat(result));

fullCalendar events not showing even though correct JSON feed

As a bunch of others I have a problem getting my JSON feed events to render in the calendar. The problem is often wrong JSON formating, but this is not the case since I've validated it with JSONlint and hardcoded the JSON feed in Site.Master with positive result.
FireBug is getting the JSON response correctly but it is still not showing up in fullCalendar. I'm out of ideas.
The FireBug response:
[{"id":1,"title":"TESTTITLE","info":"INFOINFOINFO","start":"2012-08-20T12:00:00","end":"2012-08-20T12:00:00","user":1}]
JSON.aspx
public partial class JSON : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Get events from db and add to list.
DataClassesDataContext db = new DataClassesDataContext();
List<calevent> eventList = db.calevents.ToList();
// Select events and return datetime as sortable XML Schema style.
var events = from ev in eventList
select new
{
id = ev.event_id,
title = ev.title,
info = ev.description,
start = ev.event_start.ToString("s"),
end = ev.event_end.ToString("s"),
user = ev.user_id
};
// Serialize to JSON string.
JavaScriptSerializer jss = new JavaScriptSerializer();
String json = jss.Serialize(events);
Response.Write(json);
Response.End();
}
}
Site.master
<link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
<link href='fullcalendar/fullcalendar.css' rel='stylesheet' type='text/css' />
<script src='jquery/jquery-1.7.1.min.js' type='text/javascript'></script>
<script src='fullcalendar/fullcalendar.js' type='text/javascript' ></script>
<script type="text/javascript">
$(document).ready(function () {
$('#fullcal').fullCalendar({
eventClick: function() {
alert('a day has been clicked!');
},
events: 'JSON.aspx'
})
});
</script>
I've been scanning related questions for days but none of them seems to fix mine...
Try this , you have to have a webmethod in aspx file that fullcalendar can call asynchronously
$(document).ready(function () {
$('#fullcal').fullCalendar({
eventClick: function() {
alert('a day has been clicked!');
},
events: function (start, end, callback) {
$.ajax({
type: "POST", //WebMethods will not allow GET
url: "json.aspx/GetEvents", //url of a webmethod - example below
data: "{'userID':'" + $('#<%= hidUserID.ClientID %>').val() + "'}", //this is what I use to pass who's calendar it is
//completely take out 'data:' line if you don't want to pass to webmethod - Important to also change webmethod to not accept any parameters
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (doc) {
var events = []; //javascript event object created here
var obj = $.parseJSON(doc.d); //.net returns json wrapped in "d"
$(obj.event).each(function () { //yours is obj.calevent
events.push({
title: $(this).attr('title'), //your calevent object has identical parameters 'title', 'start', ect, so this will work
start: $(this).attr('start'), // will be parsed into DateTime object
end: $(this).attr('end'),
id: $(this).attr('id')
});
});
callback(events);
}
});
}
})
then this would be in json.aspx
[WebMethod(EnableSession = true)]
public static string GetEvents(string userID)
{
DataClassesDataContext db = new DataClassesDataContext();
List<calevent> eventList = db.calevents.ToList();
// Select events and return datetime as sortable XML Schema style.
var events = from ev in eventList
select new
{
id = ev.event_id,
title = ev.title,
info = ev.description,
start = ev.event_start.ToString("s"),
end = ev.event_end.ToString("s"),
user = ev.user_id
};
// Serialize to JSON string.
JavaScriptSerializer jss = new JavaScriptSerializer();
String json = jss.Serialize(events);
return json;
}

Categories