I am trying to convert a C# list object to the correct format for a Flot Bar chart. For some reason I just can't seem to get it done correctly. I have tried several different methods. The JSON I am returning is valid JSON and the list is valid but for some reason the Flot chart wants the data in a different format. Any help would be appreciated. Thank you!
Here is the converted C# List to JSON Array
[{"color":"red","data":["Agriculture",0,2]},{"color":"red","data":["Healthcare",0,1]},{"color":"red","data":["Manufacturing",0,0]},{"color":"red","data":["Retail",0,0]},{"color":"red","data":["Information Technology",0,0]}]
I use this method to do so:
$.ajax({
type: "POST",
url: "Summary.asmx/getBarChartSeriesData",
data: JSON.stringify({ userid: userid }),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
barSummaryData = response.d;
var jsonArray = JSON.parse(response.d);
//this format seems to work
//var data = [{ data: [[0, 1]], color: "red" }, { data: [[1, 2]], color: "yellow" }, { data: [[2, 3]], color: "green" }];
var plot =
$.plot($('#barSummaryPlaceholder'), jsonArray, {
series: {
bars: {
show: true,
barWidth: 0.3,
align: "center"
}
},
xaxis: {
ticks: ticks
},
grid: { hoverable: true, clickable: true }
});
},
failure: function (msg) {
$('#barSummaryPlaceholder').text(msg);
}
});
Here is the C# Method in the ASMX:
public string getSummaryBarChartSeriesData(int userid)
{
List<Series> SeriesData = new List<Series>();
DataTable dt = new DataTable();
dt.Clear();
dt = chartcode.RetrieveSummaryBarChartData(userid);
int countOfRows = 0;
foreach (DataRow row in dt.Rows)
{
List<object> objData = new List<object>();
objData.Add(row["Name"].ToString());
objData.Add(countOfRows);
objData.Add(Convert.ToInt32(row["CountOfStudents"]));
SeriesData.Add(
new CareerClusterSeries
{
data = objData,
color = "red"
});
}
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(SeriesData);
return json;
}
For some reason the C# json string is in the valid format for JSON itself but NOT the correct format for Flot charts which is the chart system I am trying to use.
First, from the documentation Flot Reference: Data Format, the data field should be an array of arrays of numbers, e.g.:
{
label: "y = 3",
data: [[0, 3], [10, 3]]
}
In contrast, you have an flat array of numbers with a string mixed in: {"data":["Agriculture",0,2], "color":"red",}. What is the purpose of the string -- is it the series label?
Next, did you forget to increment countOfRows? It's always zero in your code.
Assuming you wanted to increment the count and set row["Name"] to be the series label, the following should produce JSON that complies with the API:
public class Series
{
public string color { get; set; }
public List<IList<double>> data { get; set; }
public string label { get; set; }
}
And then:
public string getSummaryBarChartSeriesData(int userid)
{
var SeriesData = new List<Series>();
DataTable dt = chartcode.RetrieveSummaryBarChartData(userid);
int countOfRows = 0;
foreach (DataRow row in dt.Rows)
{
var rawData = new List<IList<double>>();
rawData.Add(new double[] { countOfRows++, Convert.ToInt32(row["CountOfStudents"]) });
//objData.Add(row["Name"].ToString());
SeriesData.Add(
new CareerClusterSeries
{
data = rawData,
color = "red",
label = row["Name"].ToString(), // Guessing you wanted this.
});
}
var jsonSerialiser = new JavaScriptSerializer();
var json = jsonSerialiser.Serialize(SeriesData);
return json;
}
Related
I am trying to create a chart (using CharJs.js) with multiple data sets and have it displayed in my MVC project.
The idea is to not have the datasets manually predefined and then access each one of it in my view. This has to be built dynamically based on how many objects I have in a list.
This is my Model:
[DataContract]
public class DataPoint : IDataPoint
{
public DataPoint(string label, double y)
{
this.Label = label;
this.Y = y;
}
//Explicitly setting the name to be used while serializing to JSON.
[DataMember(Name = "label")]
public string Label { get; set; }
//Explicitly setting the name to be used while serializing to JSON.
[DataMember(Name = "y")]
public Nullable<double> Y { get; set; }
//public List<double> Y { get; set; }
}
My Controller:
public async Task<ActionResult> ShowDetails(int ProductId, string PartId, string SupplierName, string fromSearchString, int? fromPage)
{
List<string> DbSupplierList = await _itScopeRepository.GetSupplierByPartId(Convert.ToInt32(PartId));
var ItScopeProduct = _itScopeRepository.GetProductById(ProductId);
ItScopeProduct.Supplier = SupplierName;
ItScopeProduct.SupplierList = DbSupplierList;
ViewBag.FromSearchString = fromSearchString;
ViewBag.FromPage = fromPage;
var obj = await CreateLineChart(DbSupplierList, PartId);
ItScopeProduct.DataPoints = obj;
return View("DetailsView", ItScopeProduct);
}
In my case here, the DataPoints is of type List<List<DataPoint>> and the list is being unfold in my View:
And this is my view:
<!DOCTYPE HTML>
<html>
<head>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script type="text/javascript">
window.onload = function () {
var dataSecond = {
type: "line",
name:'#Html.Raw(JsonConvert.SerializeObject(Model.Supplier))',
showInLegend: true,
dataPoints: #Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[0]))
};
var dataSecond2 = {
type: "line",
name:"Dexxit",
showInLegend: true,
dataPoints: #Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[1]))
};
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
title: {
text: "Product price history"
},
axisY: {
includeZero: false
},
toolTip: {
shared: true
},
data: [dataSecond, dataSecond2]
});
chart.render();
}
</script>
</head>
<body>
<div id="chartContainer" style="height: 370px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
</body>
</html>
As you can see, right now I am taking each Object from the list manually and I would like to have it integrated in a loop where it creates an array of objects which will then be passed to my chart dataset.
I have tried something like this:
var testing;
var listOfDataPoints = [];
for(var i = 0; i < #Model.DataPoints.Count; i++){
testing = {
type: "line",
name: '#Html.Raw(JsonConvert.SerializeObject(Model.Supplier))',
showInLegend: true,
dataPoints: #Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[i]))
};
listOfDataPoints.push(testing);
}
But unfortunately I cannot pass a javascript int value to my C# model, therefore making this solution unusable.
Now my question is: Is it possible to loop through my List of objects and create n amount (base on how many items are in my list)of javascript objects and have them inserted into an array?
The js obj should have the following structure:
var myDataset = {
type: "line",
name: '#Html.Raw(JsonConvert.SerializeObject(Model.Supplier))',
showInLegend: true,
dataPoints: #Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[i]))
}
Ps. I am not very experienced with javascript, reason for why I am reaching for some guidance since I haven't found anything similar to what I need.
EDIT
I have tried the other way around: Having a c# loop and execute a javascript function where i am creating my objects.
var yest = [];
var listOfPoints = [];
function addMarker(supplier, datapo)
{
yest = {
type: "line",
name: "Dexxit",
showInLegend: true,
dataPoints: datapo
};
listOfPoints.push(yest);
}
#for(int i = 0; i < Model.DataPoints.Count; i++)
{
#:addMarker('#Html.Raw(JsonConvert.SerializeObject(Model.Supplier))', #Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[i])));
}
But when i am assigning listOfPoints to my dataset, it shows an empty chart. Any ideas why?
Manage to find a working solution based on my last edit:
Had some small changes on my Controller and that was to change one of my Model (the one passed to my View) functions from List<List<DataPoint>> DataPoints {get;set;} to `List>> DataPoint{get;set;}
My new Controller:
public async Task<ActionResult> ShowDetails(int ProductId, string PartId, string SupplierName, string fromSearchString, int? fromPage)
{
List<string> DbSupplierList = await _itScopeRepository.GetSupplierByPartId(Convert.ToInt32(PartId));
var ItScopeProduct = _itScopeRepository.GetProductById(ProductId);
ItScopeProduct.Supplier = SupplierName;
ItScopeProduct.SupplierList = DbSupplierList;
ViewBag.FromSearchString = fromSearchString;
ViewBag.FromPage = fromPage;
var obj = await CreateLineChart(DbSupplierList, PartId);
List<KeyValuePair<string, List<IDataPoint>>> ConvertToInterface = new List<KeyValuePair<string, List<IDataPoint>>>();
foreach (var item in obj)
{
ConvertToInterface.Add(new KeyValuePair<string, List<IDataPoint>>(item.Key, item.Value.ToList<IDataPoint>()));
}
ItScopeProduct.DataPoints = ConvertToInterface;
return View("DetailsView", ItScopeProduct);
}
Updated View:
<!DOCTYPE HTML>
<html>
<head>
<script src="~/Scripts/jquery-1.7.1.js"></script>
<script type="text/javascript">
window.onload = function () {
var listOfDataPoints = [];
var MyObj;
function addMarker(supplier, datapo)
{
var yest = {
type: "line",
name: supplier,
showInLegend: true,
dataPoints: datapo
};
return yest;
}
#for(int i = 0; i < Model.DataPoints.Count; i++)
{
#:MyObj = addMarker('#Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[i].Key))', #Html.Raw(JsonConvert.SerializeObject(Model.DataPoints[i].Value)));
#:listOfDataPoints.push(MyObj);
}
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
title: {
text: "Product price history"
},
axisY: {
includeZero: false
},
toolTip: {
shared: true
},
data: listOfDataPoints
});
chart.render();
}
</script>
</head>
<body>
<div id="chartContainer" style="height: 370px; width: 100%;"></div>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
</body>
</html>
My chart is now dynamically built and it can show data based on what is in my Model.DataPoints.
I hope this can be of some help for someone in the same position.
i am trying to retrieving data by custom searching. my code work properly, but when i try to filter some data from the input box. the process, get stuck. Please can anyone tell me what I m forgotting ?
My JQuery
//this work fine retrieving data by only if i search using "Search box"
var dataTableInstance = $("#dataTable").DataTable({
bServerSide: true,
sAjaxSource: 'AccountingMovementsService.asmx/GetAccountingMovements',
"processing": true,
sServerMethod: 'POST',
columns: [
{
'data': 'Payment'
},
{
'data': 'Account',
},
{
'data': 'customer',
}
]
});
//here I make all input box under footer columns (work fine)
$('#dataTable tfoot th').each(function () {
var title = $(this).text();
$(this).html("<input type='text' placeholder='" + title + "' />");
});
//And here i get stuck processing ... and data not come
dataTableInstance.columns().every(function() {
var dataTableColumn = this;
$(this.footer()).find('input').on('keyup change', function () {
dataTableColumn.search(this.value).draw();
});
});
If i use NOT SERVER-SIDE all work fine
My c# code is
[WebMethod]
public void GetAccountingMovements(int iDisplayLength, int iDisplayStart, int iSortCol_0, string sSortDir_0, string sSearch)
{
int displayLength = iDisplayLength;
int displayStart = iDisplayStart;
int sortCol = iSortCol_0;
string sortDir = sSortDir_0;
string search = sSearch;
int filteredCount = 0;
var accountingTransactions = new List<AccountMovement>();
string cs = ConfigurationManager.ConnectionStrings["Sg4DevMaster"].ConnectionString;
using (SqlConnection conn = new SqlConnection(cs))
{
SqlCommand cmd = new SqlCommand("spGetAccountingTransactions", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "DisplayLength",
Value = displayLength
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "DisplayStart",
Value = displayStart
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "SortCol",
Value = sortCol
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "SortDir",
Value = sortDir
});
cmd.Parameters.Add(new SqlParameter
{
ParameterName = "Search",
Value = search
});
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
AccountMovement am = new AccountMovement();
filteredCount = Convert.ToInt32(rdr["totalCount"]);
am.payment = Convert.ToDouble(rdr["payment"]);
am.Account = Convert.ToDouble(rdr["account"]);
am.Customer = rdr["Customer"].ToString();
accountingTransactions.Add(am);
}
}
var result = new
{
iTotalRecords = GetAccountingMovementsTotalCount(),
iTotalDisplayRecords = filteredCount,
aaData = accountingTransactions
};
JavaScriptSerializer js = new JavaScriptSerializer();
Context.Response.Write(js.Serialize(result));
}
All work fine using "the main search input box" in the DataTable Plugin, but it get stuck when put some data in one of custom input box placed in the footer
Thank for you time!
If you go to my GitHub https://github.com/bindrid/DataTablesServerSide take a look at the c# classes. That is how I take the parameters provided by DataTable and turn it into a usable c# object.
Also listed there is my web method that uses those classes.
Below is the DataTables logic, including your search stuff and it all works.
var table = $('#example').DataTable({
"processing": true,
"serverSide": true,
"rowCallback": function (row, data) {
if ($.inArray(data.employeeId, selected) !== -1) {
table.row(row).select();
}
},
"infoCallback": function (settings, start, end, max, total, pre) {
var api = this.api();
var pageInfo = api.page.info();
return 'Page '+ (pageInfo.page+1) +' of '+ pageInfo.pages + " ";
},
rowId:"employeeId",
"createdRow": function (row, data, dataIndex) {},
"columns": [
{ "data": "name" },
{ "data": "position" },
{ "data": "office" },
{ "data": "extn" },
{ "data": "start_date" },
{ "data": "salary" }
],
"select":"multi",
"lengthMenu": [5, [10, 15, 25, 50, -1], [5, 10, 15, 25, 50, "All"]],
"pageLength": 5,
"ajax": {
contentType: "application/json; charset=utf-8",
url: "wsSample.asmx/GetDTDataUnserializedObject",
type: "Post",
data: function (dtParms) {
// notice dtParameters exactly matches the web service
return JSON.stringify({ dtParameters: dtParms });
},
// Data filter is a part of ajax and lets you look at the raw
dataFilter: function (res) {
// You probably know by know that WebServices
// puts your data in an object call d. these two lines puts it
// in the form that DataTable expects
var parsed = JSON.parse(res);
return JSON.stringify(parsed.d);
},
error: function (x, y) {
debugger;
console.log(x);
}
},
order: [[0, 'asc']]
});
// add search boxes to footer
$('#example tfoot th').each(function () {
var title = $(this).text();
$(this).html("<input type='search' placeholder='" + title + "' />");
});
//And here i get stuck processing ... and data not come
table.columns().every(function () {
var dataTableColumn = this;
$(this.footer()).find('input').on('keyup change', function () {
dataTableColumn.search(this.value).draw();
});
});
I am using select2 v4.0 https://select2.github.io/ in an asp mvc project and I want display a simple dropdown from dynamic Data
The old way of version 3.6 doesn't work anymore:
I have a c# methode:
public JsonResult GetSrcMethod()
{
var list = new[]
{
new { id= 0, text= "Smith" },
new { id= 1, text= "John" },
new { id= 2, text= "Philippe" },
}.ToList();
Object json = JsonConvert.SerializeObject(list);
return Json(json, JsonRequestBehavior.AllowGet);
}
Thus, the data returned is:
[{"id":0,"text":"Smith"},{"id":1,"text":"John"},{"id":2,"text":"Philippe"}]
And I have a javascript code which worked on previous version 3.6:
$(".example-select2").select2({
ajax: {
dataType: 'json',
url: '#Url.Action("GetSrcLanguages", "GetCheckSet")',
results: function (data) {
return {results: data};
}
}
});
It render an empty dropdownlist that displays 'No result found'
Do you know how to do it in v4.0?
Id is not the same as id, properties on JavaScript objects are case-sensitive. The same applies to Text and text as well, you want to use the all-lowercase versions.
public JsonResult GetSrcLanguages()
{
var list = new[]
{
new { id = 0, text = "Smith" },
new { id = 1, text = "John" },
new { id = 2, text = "Philippe" },
}.ToList();
Object json = JsonConvert.SerializeObject(list);
return Json(json, JsonRequestBehavior.AllowGet);
}
Also, the ajax.results method was renamed to ajax.processResults in 4.0.0 to avoid conflicting with AJAX transports that have an existing results method. So your JavaScript should actually look like
$(".example-select2").select2({
ajax: {
dataType: 'json',
url: '#Url.Action("GetSrcLanguages", "GetCheckSet")',
processResults: function (data) {
return {results: data};
}
}
});
I need to bind a Kendo grid to a model class. I am returning the same from controller using Json result but the gird is not getting bind. Also find below code snippets used.
Model:
public DataTable ErrorData { get; set; }
public List<string> Groups { get; set; }
public Dictionary<string, System.Type> ErrorColumns { get; set; }
Controller :
public JsonResult PopulateData()
{
ErrorPage _objError = new ErrorPage();
//Getting the details from Database
_objError.ErrorData = dbl.GetDataTable(DbConnectionString,Table,whereCondition, columns);
//Poplulating the Column list as it is dynamically generated every time as per the filter on front end(View)
//Column description: Name and Type
var columnlist = new Dictionary<string, System.Type>();
foreach (System.Data.DataColumn column in _objError.ErrorData.Columns)
{
var t = System.Type.GetType( column.DataType.FullName );
columnlist.Add(column.ColumnName, t);
}
_objError.ErrorColumns = columnlist;
return Json(_objError);
}
View:
This is a code return on button click
$.post(path, { application: app, columns: columns, machine: machine, pages: pages,
startDate: startDate, endDate: endDate }, function (result) {
var grid = $("#ErrorLog").data(result);
grid.dataSource.read();
grid.refresh();
});
This is Kendo grid code which also get bind to data on page load:
#(Html.Kendo().Grid<dynamic>()
.Name("ErrorLog")
.Columns(columns =>
{
//Define the columns
foreach (var c in Model.ErrorColumns)
columns.Bound(c.Value, c.Key);
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
foreach (System.Data.DataColumn column in Model.ErrorData.Columns)
{
model.Field(column.ColumnName, column.DataType);
}
})
.Read(read => read.Action("populateData", "Common"))
)
.Groupable()
.Sortable(s => s.AllowUnsort(true))
.Filterable(ftb => ftb.Mode(GridFilterMode.Menu))
.Pageable(pageable => pageable
.Refresh(true)
.PageSizes(true)
//.ButtonCount(5)
)
)
The column list is populated properly. but i am not sure about the returning the JsonResult to a kendo grid. Kindly help on how to bind a kendo grid using Json result.
Here we go with the solution:
This is my controller where i have serialized the object we are trying to send to View:
public JsonResult populateData(string application, string columns, string machine, string pages, string startDate, string endDate)
{
ErrorPage _objError = new ErrorPage();
var ErrorResult = _objError.GetErrorData(application, columns, machine, pages, startDate, endDate);
//Column description: Name and Type
var columnlist = new Dictionary<string, System.Type>();
foreach (System.Data.DataColumn column in _objError.ErrorData.Columns)
{
var t = System.Type.GetType(column.DataType.FullName);
columnlist.Add(column.ColumnName, t);
}
_objError.ErrorColumns = columnlist;
var result = JsonConvert.SerializeObject(ErrorResult.ErrorData, Formatting.Indented,
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
return Json(result, JsonRequestBehavior.AllowGet);
}
Here is my view which binds the datatable send from controller to Kendo grid:
$.ajax({
type: "POST",
url: '#Url.Content("~/Common/PopulateData")',
contentType: "application/json;charset=utf-8",
dataType: 'json',
data: JSON.stringify({ application: app, columns: columns, machine: machine, pages: pages, startDate: startDate, endDate: endDate }),
success: function (data) {
$('#ErrorLog').data("kendoGrid").dataSource.data(JSON.parse(data));
}
});
Thanks
I have been reading ALL of the documentation on this and I still cannot get it to work.
I have a Web API which provides a JSON object. It's a list of 22 things. Just 22 lines of text.
I want to take these and form a TreeView. Each of these 22 strings will have items under them but I just want to get the first part working.
My first question is, how do I extract data from an API and populate a treeView with it?
On my main page, I have this:
<div id="treeView"></div>
On my JavaScript file I have this:
$("#treeView").kendoTreeView({
checkboxes: true,
dataSource: {
transport: {
read: {
url: "http://...",
dataType: "json"
}
}
}
});
When I try to run the page, I get "Request failed." [Retry]
If I open up a browser and go to this URL, data is returned fine as a JSON object.
What am I doing wrong here?
EDIT -
Code that is returning the JSON:
public List<string> getNotificationByUser(int id)
{
List<string> notificationTitles = new List<string>();
foreach (var notification in notifications)
{
notificationTitles.Add(notification.ToString());
}
return notificationTitles;
}
Ok! I've been able to reproduce your error. The question is that 22 lines of text are not a valid JSON.
Returning something like:
This
is
a
test
Is not a valid JSON.
But a valid JSON is not enough, you should return something like this:
[
{ "text": "This" },
{ "text": "is" },
{ "text": "a" },
{ "text": "test" }
]
I.e.: The result should be an array of objects where each object has a text field.
NOTE I know that it does not have to be called text but for simplicity I used it since it is the default value.
I figured out all of my answers:
function CreateNotificationTree(userId)
{
debugger;
var data = new kendo.data.HierarchicalDataSource({
transport: {
read: {
url: "../api/notifications/byuserid/" + userId,
contentType: "application/json"
}
},
schema: {
model: {
children: "notifications"
}
}
});
$("#treeview").kendoTreeView({
dataSource: data,
loadOnDemand: true,
dataUrlField: "LinksTo",
checkboxes: {
checkChildren: true
},
dataTextField: ["notificationType", "NotificationDesc"],
select: treeviewSelect
});
function treeviewSelect(e)
{
var node = this.dataItem(e.node);
window.open(node.NotificationLink, "_self");
}
}
[HttpGet]
public List<Node> getNotifications(int id)
{
var bo = new HomeBO();
var list = bo.GetNotificationsForUser(id);
var notificationTreeNodes = (from GBLNotifications n in list
where n.NotificationCount != 0
select new NotificationTreeNode(n)).ToList();
var li = notificationTreeNodes.Select(no => new Node
{
notificationType = no.NotificationNode.NotificationType + " " + "(" + no.NotificationNode.NotificationCount + ")", notifications = bo.GetNotificationsForUser(id, no.NotificationNode.NotificationTypeId).Cast<GBLNotifications>().Select(item => new Notification
{
ID = item.NotificationId, NotificationDesc = item.NotificationDescription, Params = new List<NotificationParam>
{
new NotificationParam
{
ParamName = item.Param1, ParamVal = item.ParamValue1
},
new NotificationParam
{
ParamName = item.Param2, ParamVal = item.ParamValue2
},
new NotificationParam
{
ParamName = item.Param3, ParamVal = item.ParamValue3
},
new NotificationParam
{
ParamName = item.Param4, ParamVal = item.ParamValue4
},
new NotificationParam
{
ParamName = item.Param5, ParamVal = item.ParamValue5
},
},
ActionPageName = item.ActionPageName
}).ToList()
}).ToList();
li.ForEach(i => i.notifications.ForEach(x => x.SetNotificationLink()));
return li;
}