How do I update a KendoUI chart via javascript JSON? - asp.net-mvc

So I have a chart which is configured using the MVC style configuration...
#(Html.Kendo().Chart<DIMVC.ViewModel.CompanyProduction>(Model.CompanyProduction)
.Name("Chart")
.Title("Files sent")
.Legend(legend => legend
.Position(ChartLegendPosition.Bottom)
)
.ChartArea(chartArea => chartArea
.Background("transparent")
)
.SeriesDefaults(seriesDefaults =>
seriesDefaults.Line().Style(ChartLineStyle.Smooth)
)
.Series(series => {
series.Line(model => model.SentFiles).Name("Sent Files");
... { lots more series added here }
}
.CategoryAxis(axis => axis
.Categories(model => model.MonthDisplay)
.Labels(labels => labels.Rotation(-90))
)
.ValueAxis(axis => axis.Numeric()
.Labels(labels => labels.Format("{0:N0}"))
.MajorUnit(10000)
)
.Tooltip(tooltip => tooltip
.Visible(true)
.Format("{0:N0}")
)
.Events(e => e
.SeriesClick("onSeriesClick")
)
)
I also have a slider on the page. When the slider value is changed I handle this event.
#(Html.Kendo().RangeSlider()
.Name("yearRange")
.Min(2000)
.Max(DateTime.Today.Year)
.SmallStep(1)
.LargeStep(5)
.Values(Model.MinYear, Model.MaxYear)
.Events(e => e.Change("yearRangeChange"))
)
javascript method
function yearRangeChange(e)
{
var url = "/FetchData/";
$.ajax({
type: "GET",
url: url,
data: { startYear: e.values[0], endYear: e.values[1] },
dataType: "json",
success: function (json) {
$("#DINETChart").kendoChart({
dataSource: {
data: json
}
});
var chart = $("#DINETChart").data("kendoChart");
chart.refresh();
}
});
}
now when the chart is updated the grid is just blank.
The json request is successfully called and the data is retrieved.
but after the chart is populated the chart is blank.
has anyone got any suggestions?
* EDIT *
adding a sample of the JSON returned
"[{\"CompanyID\":1,\"Year\":2011,\"Month\":8,\"SentFiles\":1666,\"ReceivedFiles\":1632,\"SentData\":12803.674593292486,\"ReceivedData\":11908.047586546765,\"Note\":null,\"MonthDisplay\":\"Aug\",\"CompanyDisplay\":null},{\"CompanyID\":1,\"Year\":2013,\"Month\":10,\"SentFiles\":21004,\"ReceivedFiles\":20387,\"SentData\":157376.825542573,\"ReceivedData\":152878.87845794103,\"Note\":null,\"MonthDisplay\":\"Oct\",\"CompanyDisplay\":null},{\"CompanyID\":1,\"Year\":2013,\"Month\":4,\"SentFiles\":9989,\"ReceivedFiles\":9880,\"SentData\":74913.53277995327,\"ReceivedData\":75145.16331588416,\"Note\":null,\"MonthDisplay\":\"Apr\",\"CompanyDisplay\":null},{\"CompanyID\":1,\"Year\":2013,\"Month\":11,\"SentFiles\":25956,\"ReceivedFiles\":25249,\"SentData\":196155.8977337967,\"ReceivedData\":189320.44546897494,\"Note\":null,\"MonthDisplay\":\"Nov\",\"CompanyDisplay\":null}]"
I would also like to point out that if I add this
.DataSource(ds => ds.Read(read =>
read.Action("FetchData", "Home", new { startYear = 2012, endYear = 2013 })
))
to my chart configuration, this will populate the chart fine, without using the page Model.
i.e. The data is correct for the chart.

The data source expects an array as value for its data, but it looks like the json variable you're assigning contains a JSON string (at least if the string you added to the question is what you're seeing on the client in the json var). jQuery should normally parse that for you if you set dataType to "json" (not sure why that is not happening for you - you should double check that the dataType param is set correctly).
You can try parsing it yourself; apart from that, you should also use chart.setDataSource() instead of creating a new chart. They way you're doing it now, you're simply replacing your original chart with its configuration with a chart that has no configuration. Try something like this in your callback:
var data = JSON.parse(json);
var chart = $("#DINETChart").data("kendoChart");
var dataSource = new kendo.data.DataSource({
data: data
});
chart.setDataSource(dataSource);
Note that in your yearRangeChange function, you're trying to call refresh on the chart outside of your ajax success call. You don't need to refresh when you use setDataSource, but even if you needed to do that, it would have to be in the callback. Otherwise it happens before the ajax call completes.

Related

Sort Kendo Multiselects selected Items by DataTextField

We are using kendo multiselect with mvc wrappers. Everything on the setup works fine, but the selected items are sorted by the data value field. I simply want them to be sorted by the data text field, but nothing worked so far.
#(Html.Kendo().MultiSelectFor(m => m.SelectedPersonIds)
.HtmlAttributes(new { style = "width: 400px" })
.DataTextField("Name")
.DataValueField("PersonID")
.Filter("contains")
.Height(400)
.DataSource(ds =>
{
ds.Read(read =>
{
read.Action("GetPersons", "Person", new { area = "" });
});
})
.ItemTemplateId("detailTemplate")
.TagTemplateId("valueTemplate")
)
This is the working version. I tried adding
ds.Custom().Sort(s => s.Add("Name").Ascending());
and other approaches, but still no luck. The initial data, coming from the server, is sorted and therefore the list you select from is sorted perfectly (by Name).
How can i achieve that the selected items are also sorted by Name instead of by ID?
Thanks in advance.
Do not manually rearrange the DOM elements. Doing this will break the mapping between the displayed items and the internal data. If you were to manually rearrange the DOM elements, then deselecting an item will cause a different data item to be deselected in the underlying data. Binding back to the server will yield incorrect results.
Here is a correct way to order it, given that the value field is PersonID but you want it sorted by Name
function orderMultiSelect(multi) {
const dataItems = multi.dataItems();
dataItems.sort(
(a, b) => {
const textA = a.Name;
const textB = b.Name;
return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
}
);
const values = dataItems.map(di => di.PersonID);
multi.value(values);
}
function onMultiselectChange(e) {
orderMultiselect(e.sender);
}
You would then bind this handler function to the to the DataBound and Change events:
#(Html.Kendo().MultiSelectFor(m => m.SelectedPersonIds)
.HtmlAttributes(new { style = "width: 400px" })
.DataTextField("Name")
.DataValueField("PersonID")
.Filter("contains")
.Height(400)
.DataSource(
ds =>
{
ds.Read(
read =>
read.Action("GetPersons", "Person", new { area = "" })
);
}
).ItemTemplateId("detailTemplate")
.TagTemplateId("valueTemplate")
.Event(
e =>
e.DataBound("onMultiselectChange")
.Change("onMultiselectChange")
)
)
http://plnkr.co/edit/0gS9SDeccgOmfsGp?preview
I don't know is there is ASP.NET solution but i can give you JavaScript to solve it:
function onMultiselectChange(e) {
e.sender.tagList.find('> li').sort(function (a, b) {
return $(a).text() > $(b).text();
}).appendTo(e.sender.tagList);
}
});
You can apply it to your ASP.NET multiselect like this:
.Events(e =>
{
e.Change("onMultiselectChange")
})

Change dropdownlist to autocomplete in scheduler popup editor in Kendo MVC

For example, I bind the resource as follows.
.Resources(resource =>
{
resource.Add(m => m.UserName)
.Title("Staff")
.Name("Staff")
.DataTextField("Text")
.DataValueField("Value")
.DataSource(source => source
.Read(read => read.Action("GetStaffList", "Scheduler"))
);
})
When the editor popups, the staff input has type of dropdown list which contains all the Staff in database.
Question: How to change it to an autocomplete widget with server filtering by staff's name for example.
Thank you.
I would jump into JavaScript by hooking up a event on edit to the grid, then you can do it there doing something like this
function onEdit(e) {
//Autocompleter
$("#Staff").kendoAutoComplete({
dataSource: {
serverFiltering: true,
transport: {
read: { url: "/Staff/GetListForAutocompleter" },
parameterMap: function (data, action) {
var newParams = { filter: $("#Staff").val(), filter2: 'something' };
return newParams;
}
}
}
});
}

Kendo Grid doesn't display JSON Dates

I'm using a Kendo Grid, built with their MVC Helpers to display some remote JSON data.
Everything works fine except the date columns.
Here's my setup.
View:
#(Html.Kendo().Grid<TrainingDTO>().Name("grid_training")
.Columns(c => {
c.Bound(a => a.Id).Width(50);
c.Bound(a => a.Start).ClientTemplate("#= (Start == null) ? ' ' : kendo.toString(Start, 'dd-MM-yyyy') #");
c.Bound(a => a.End).Format("{0:dd/MM/yyyy HH:mm:ss}");
c.Bound(a => a.Description);
})
.Pageable()
.Scrollable().DataSource(ds => ds.Ajax().PageSize(5).Model(m => m.Id(p => p.Id)).Read(R => R.Action("GridData", "Home", new { providerId = Model.Id }).Type(HttpVerbs.Post)))
)
And the controller:
[HttpPost]
public JsonResult GridData([DataSourceRequest]DataSourceRequest request) {
var data = new Service().LoadSomeData().ToDataSourceResult(request, A => new {
Id = A.Id,
Start = A.Start,
End = A.End,
Description = A.Description
});
return Json(data, JsonRequestBehavior.AllowGet);
}
Which returns (in json)
{
"Data": [
{
"Id": 1,
"Start": "\/Date(1412031600000)\/",
"End": "\/Date(1415318400000)\/",
"Description": "test teste test"
}
],
"Total": 1,
"AggregateResults": null,
"Errors": null
}
The Start and End columns appear empty. These properties on the TrainingDTO POCO are DateTime Nullables (ie, DateTime?)
I've tried many options to format the data but to no avail.
Is there a way to print these JSON dates on the grid (without resorting to formatting them as strings on the controller) ?
I have had this problem before.
I assume you are looking to use UK date format rather than the default US format.
If you take off the formatting I expect you will see the dates formatted correctly.
As you appear to be using a flattened model (date's don't work correctly in complex viewmodels) then the simplest thing to do is add the culture file into your project and then set it to UK so that everything is picked up correctly.
so in your layout page put this after the kendo scripts:
<script src="/Scripts/kendo/{you version here}/cultures/kendo.culture.en-GB.min.js"></script>
<script type="text/javascript">
kendo.culture("en-GB");
</script>
If the culture files are not part of the project just go through the telerik upgrade and include them or just copy them into the project.

Kendo Grid and one row of JSON data and a single row of data

I feed JSON results to My Kendo Grid; seems like when I have one row of data, the grid can't function?
Following works:
<DocumentElement>
<ResultXml>
<NoData>1</NoData>
</ResultXml>
<ResultXml>
<NoData>2</NoData>
</ResultXml>
</DocumentElement>";
and this doesn't work:
<DocumentElement>
<ResultXml>
<NoData>1</NoData>
</ResultXml>
</DocumentElement>";
EDIT to clear out above xml is converted to json before being fed to the grid (I included the xml version of the json for readability purposes)
Obviously above is xml; after using Newtonsoft.Json.JsonConvert, I get the following JSON results to feed to my grid (none of which works):
{"DocumentElement":{"ResultXml":"Nothing to display"}}
{"DocumentElement":{"ResultXml":{"field":"Nothing to display"}}}
Following works, but I want to avoid sending an empty field if I don't have to
{"DocumentElement":{"ResultXml":[{"NoData":null},{"NoData":"Nothing to display"}]}}
End of Edit
here's my Kendo Grid:
$("#grid").kendoGrid({
sortable: true,
groupable: true,
scrollable: true,
height: "600px",
pageable: { pageSizes: 9 },
dataSource:
{
transport:
{
read: function (options) {
$.ajax("/Controller/Action?param=" + paramVal,
success: function (result) {
var jResult = $.parseJSON(result);
options.success(jResult.DocumentElement.ResultXml);
});
}
}
},
});
I guess I can hardcode the json string when sending it back to client; I would've liked to have the xml version of saying I have empty dataset; but I guess this'll do, unless someone can suggest something better;
if (string.IsNullOrEmpty(xmlResult))
{
//No data:
jsonData = "{\"DocumentElement\":{\"ResultXml\":[{\"NoData\":\"Nothing to display\"}]}}";
}
else
{
//Turn xml data to Json:
var doc = new XmlDocument();
doc.LoadXml(xmlResult);
jsonData = JsonConvert.SerializeXmlNode(doc);
}
I believe the field name does not need double quotes. Ex/ name\value pair as in {name: "Bob Mazzo"}
Are you sure that there are 2 definition (one for View,the other for retrieving data) in your controller and the View calls the other one as below?
Controller:
//!!! This is for calling "CustomAjaxBinding" view
public ActionResult CustomAjaxBinding()
{
return View();
}
//!!! This is for retrieving data called from "CustomAjaxBinding" View
public ActionResult CustomAjaxBinding_Read([DataSourceRequest] DataSourceRequest request)
{
var dataContext = new SampleEntities();
//Convert to view model to avoid JSON serialization problems due to circular references.
IQueryable<OrderViewModel> result = dataContext.Orders.Select(o => new OrderViewModel
{
OrderID = o.OrderID,
ShipCity = o.ShipCity,
ShipCountry = o.ShipCountry,
ShipName = o.ShipName
});
return Json(result, JsonRequestBehavior.AllowGet);
}
View (name is "CustomAjaxBinding")
#(Html.Kendo().Grid<Kendo.Mvc.Examples.Models.Order>()
.Name("Grid")
.Columns(columns => {
columns.Bound(o => o.OrderID).Groupable(false);
columns.Bound(o => o.ShipCity);
columns.Bound(o => o.ShipCountry);
columns.Bound(o => o.ShipName);
})
.Pageable()
.Sortable()
.Filterable()
.Scrollable()
.Groupable()
.DataSource(dataSource => dataSource
.Ajax()
//!!! Call "CustomAjaxBinding_Read" not CustomAjaxBinding
.Read(read => read.Action("CustomAjaxBinding_Read", "Grid"))
)
)
Regards...

How to bind kendo mvc ui dropdownlist dynamically

I am working on asp.net mvc with Kendo UI mvc. I have two kendo dropdown lists. one for list of clinics and another of list of patients in selected clinic. But there is no direct relationship between clinic and patient to use the cascading dropdownlist. for that i have used ajax calls in dropdownlist change event and get list of patients. and this is my first dropdownlist for list clinics
#(
Html.Kendo().DropDownList()
.Name("ddlClinics")
.Events(e=>e.Change("ChangeClinic"))
.BindTo(new SelectList((List<Account.Entities.Clinic>)ViewBag.lstClinic,
"ClinicID", "ClinicName")))
and this is my second dropdownlist for listpatients
#(
Html.Kendo().DropDownList()
.Name("ddlPatients")
.BindTo(new SelectList((List<Patient>)ViewBag.Patients,
"PatId", "PatName"))))
I want to dynamically bind the list of patients to second dropdownlist when the first dropdownlist changes,
function ChangeClinic()
{
$.ajax({
url: '/Messages/GetPatient',
type: 'Post',
data: { email: '#User.Identity.Name' },
cache: false,
success: function (result) {
var ddlPatients = $('#ddlPatients').data('kendoDropDownList');
var main = [];
$.each(result, function (k, v) {
main.push({ "PatId": v.PatId, "PatName": v.PatName });
});
ddlPatients.dataTextField = "PatName";
ddlPatients.dataValueField = "PatId";
ddlPatients.dataSource.data(main);
ddlPatients.reload();
}
});
}
i am able to bind the list to dropdownlist but all items are shows as 'undefined'. so please guide me.
From what I can tell, there is a relationship between clinics and patients so you should be able to use the CascadeFrom("DropDownList1") provided in the wrappers. We use a cascading dropdownlist in a similar fashion for the relationship between school districts and schools:
#(Html.Kendo().DropDownList()
.Name("District")
.HtmlAttributes(new { style = "width:300px;" })
.BindTo(ViewBag.districts)
.DataTextField("DistrictName")
.DataValueField("DistrictID")
.OptionLabel("Select District")
)
#(Html.Kendo().DropDownList()
.Name("School")
.HtmlAttributes(new { style = "width:300px;" })
.CascadeFrom("District")
.BindTo(ViewBag.schools)
.DataTextField("SchoolName")
.DataValueField("SchoolID")
.OptionLabel("Select School")
)
If you want fill second DropDown on basis of first DropDown value.
Telerik Provided,
.CascadeTo("DropDownList2")
Please see following link for detailed information.
Cascading of Dropdown in Telerik dropdownlist
Instead of creating such array which is useless to the dataSource use:
success: function (result) {
var ddlPatients = $('#ddlPatients').data('kendoDropDownList');
var main = [];
$.each(result, function (k, v) {
main.push({ "text": v.PatId, "value": v.PatName });
});
ddlPatients.dataSource.data(main);
}
});
If you are not using
.DataSource(source =>
{
source.Read(read =>
{
read.Action ("FunctionName", "ControllerName").Data("filterDropdown1");
}).ServerFiltering(true);
})
.CascadeFrom("Dropdown1")
properties in the definition of second dropdown and you are using the definition mentioned in question above. i.e:-
#(
Html.Kendo().DropDownList()
.Name("ddlPatients")
.BindTo(new SelectList((List<Patient>)ViewBag.Patients,"PatId", "PatName"))
)
then you can bind the data to the 2nd dropdown directly in the success function of ajax post.
function ChangeClinic()
{
$.ajax({
url: '/Messages/GetPatient',
type: 'Post',
data: { email: '#User.Identity.Name' },
cache: false,
success: function (result) {
$('#ddlPatients').data('kendoDropDownList').dataSource.data(result);
//ddlPatients.reload();
}
});
}
#Note:- 1) The result value should contain the list of new patients with properties "PatId" and "PatName" based on the parameter email passed to the function "Messages" in GetPatient controller, and there will be no need for ddlpatients.reload(), infact .reload() is not supported, it will break the execution, so don't use .reload().

Resources