I am using Highsoft.Highstock .NET on my ASP.net MVC 5 application.
I create a list of single line charts directly inside the controller and send all the data to the view.
When I change the navigation (start/enddate slider at the bottom of the chart) for one chart, I would like to update all other charts to the same timeframe (all charts have the same timespan).
I would like to do this with jquery, but I am not able right now.
I think I have to use the
(I was also reading the API from Highstock but there is something different, e.g.: my charts do not have a property "chart.title.text" -> my one has "chart.title.textStr")
JS solution:
To update all charts when you change the navigator position on one of them you can use xAxis.events.afterSetExtremes event to set new extremes on all charts (you can find all charts reference in Highcharts.charts array).
Code:
var json = "[[1534512600000,217.58],[1534771800000,215.46],[1534858200000,215.04],[1534944600000,215.05],[1535031000000,215.49],[1535117400000,216.16],[1535376600000,217.94],[1535463000000,219.7],[1535549400000,222.98],[1535635800000,225.03],[1535722200000,227.63],[1536067800000,228.36],[1536154200000,226.87],[1536240600000,223.1],[1536327000000,221.3],[1536586200000,218.33],[1536672600000,223.85],[1536759000000,221.07],[1536845400000,226.41],[1536931800000,223.84],[1537191000000,217.88],[1537277400000,218.24],[1537363800000,218.37],[1537450200000,220.03],[1537536600000,217.66],[1537795800000,220.79],[1537882200000,222.19],[1537968600000,220.42],[1538055000000,224.95],[1538141400000,225.74],[1538400600000,227.26],[1538487000000,229.28],[1538573400000,232.07],[1538659800000,227.99],[1538746200000,224.29],[1539005400000,223.77],[1539091800000,226.87],[1539178200000,216.36],[1539264600000,214.45],[1539351000000,222.11],[1539610200000,217.36],[1539696600000,222.15],[1539783000000,221.19],[1539869400000,216.02],[1539955800000,219.31],[1540215000000,220.65],[1540301400000,222.73],[1540387800000,215.09],[1540474200000,219.8],[1540560600000,216.3],[1540819800000,212.24],[1540906200000,213.3],[1540992600000,218.86],[1541079000000,222.22],[1541165400000,207.48],[1541428200000,201.59],[1541514600000,203.77],[1541601000000,209.95],[1541687400000,208.49],[1541773800000,204.47],[1542033000000,194.17],[1542119400000,192.23],[1542205800000,186.8],[1542292200000,191.41],[1542378600000,193.53],[1542637800000,185.86],[1542724200000,176.98],[1542810600000,176.78],[1542983400000,172.29],[1543242600000,174.62],[1543329000000,174.24],[1543415400000,180.94],[1543501800000,179.55],[1543588200000,178.58],[1543847400000,184.82],[1543933800000,176.69],[1544106600000,174.72],[1544193000000,168.49],[1544452200000,169.6],[1544538600000,168.63],[1544625000000,169.1],[1544711400000,170.95],[1544797800000,165.48],[1545057000000,163.94],[1545143400000,166.07],[1545229800000,160.89],[1545316200000,156.83],[1545402600000,150.73],[1545661800000,146.83],[1545834600000,157.17],[1545921000000,156.15],[1546007400000,156.23],[1546266600000,157.74],[1546439400000,157.92],[1546525800000,142.19],[1546612200000,148.26],[1546871400000,147.93],[1546957800000,150.75],[1547044200000,153.31],[1547130600000,153.8]]";
var data = JSON.parse(json);
function updateExtremes() {
var currentChart = this.chart,
chartIndex = currentChart.index,
charts = Highcharts.charts,
min = currentChart.xAxis[0].min,
max = currentChart.xAxis[0].max;
charts.forEach(function(chart) {
if (chart.index !== chartIndex) {
chart.xAxis[0].setExtremes(min, max, true, false);
}
});
}
Highcharts.stockChart('container1', {
chart: {
height: 250
},
rangeSelector: {
selected: 0
},
title: {
text: 'AAPL Stock Price'
},
xAxis: {
events: {
afterSetExtremes: function() {
updateExtremes.call(this);
}
}
},
series: [{
name: 'AAPL',
data: data,
tooltip: {
valueDecimals: 2
}
}]
});
Highcharts.stockChart('container2', {
chart: {
height: 250
},
rangeSelector: {
selected: 0
},
title: {
text: 'AAPL Stock Price'
},
xAxis: {
events: {
afterSetExtremes: function() {
updateExtremes.call(this);
}
}
},
series: [{
name: 'AAPL',
data: data,
tooltip: {
valueDecimals: 2
}
}]
});
Highcharts.stockChart('container3', {
chart: {
height: 250
},
rangeSelector: {
selected: 0
},
title: {
text: 'AAPL Stock Price'
},
xAxis: {
events: {
afterSetExtremes: function() {
updateExtremes.call(this);
}
}
},
series: [{
name: 'AAPL',
data: data,
tooltip: {
valueDecimals: 2
}
}]
});
Demo:
https://jsfiddle.net/BlackLabel/74rgyq13/
JS API reference:
https://api.highcharts.com/highcharts/xAxis.events.afterSetExtremes
https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes
C# API reference:
http://dotnet.highcharts.com/Help/Highcharts/html/class_highsoft_1_1_web_1_1_mvc_1_1_charts_1_1_x_axis_events.html#aa8efb1a8237bc71a0268e5ee7e522096
http://dotnet.highcharts.com/Help/Highcharts/html/class_highsoft_1_1_web_1_1_mvc_1_1_charts_1_1_x_axis_events.html#a120bc76164638d4a76a7ee20280d54ff
Related
Recently I posted on Hight Charts where I did like to create dynamic charts based on Razor view loop. Here's the link - Dynamic Chart
I tried one of the solution provided by a SO user as follows:
<script>
async function createChart(containerName, dryArgument, operatingArgument){
let dryData = await fech(dryArgument)
let operatingData = await fech(operatingArgument)
Highcharts.chart(containerName, {
chart: {
type: 'column'
},
title: {
text: 'Monthly Average Rainfall'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Rainfall (mm)'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [
{
name: 'Dry',
data: JSON.parse(dryData)
}, {
name: 'Operating',
data: JSON.parse(operatingData)
}]
});
}
</script>
In the front-end, used this:
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-lg-12 col-md-12 col-xs-12">
//Dynamic Chart - Starts
#if (Model.aLstTopsideModuleGroupBy.ToList().Count > 0)
{
foreach (var item in Model.aLstTopsideModuleGroupBy)
{
foreach (var item2 in item)
{
int i = 0;
<div id="container#i"></div>
<p class="highcharts-description">
</p>
<script>
window.onload = function () {
createChart('#container#i',#item2.BaseDry,#item2.BaseOp);
};
</script>
i++;
}
}
}
//Dynamic Chart - Ends
</div>
</div>
</div>
I am not sure if this is the correct way to do it, but got the following exception while trying:
Uncaught SyntaxError: missing ) after argument list
Is there any way to resolve the exception? I know, am doing something doing wrong here, any idea or suggestion would be appreciated.
Update 1: Exception
You don't have your Java Script correctly set up.
First of all, fetch() does return a promise that will give you a response object once fulfilled. That response object has json() function returning a promise that will return the json as JavaScript object once fulfilled. Promises are best awaited. The start of your createChart function should look this:
async function createChart(containerName, dryArgument, operatingArgument){
let dryData = await fetch(dryArgument) /* note you have a typo in your question */
let dryJson = await dryData.json();
let operatingData = await fetch(operatingArgument)
let operatingJson = await operatingData.json();
/* rest of code here */
In the series setup of HighCharts you now need to make these changes:
series: [
{
name: 'Dry',
data: dryJson
}, {
name: 'Operating',
data: operatingJson
}]
This does assume that dryJson and operatingJson are single dimension javascript arrays with numbers in it (so [1,2,3] will work, ['1', '2', '3'] doesn't nor does {items:[{score:1}]}.
The exact setup in the Razor page is a task I leave at you, it shouldn't be that hard to verify if the outcome of the rendered page matches the actual need.
For testing purposes I created stack snippet where I use posts and users from the Stack API as Json sources. As those are a slightly different shape you see a map over its items array to get the desired array of numbers:
async function createChart(containerName, dryArgument, operatingArgument){
let dryData = await fetch(dryArgument)
let dryJson = await dryData.json();
let operatingData = await fetch(operatingArgument)
let operatingJson = await operatingData.json();
Highcharts.chart(containerName, {
chart: {
type: 'column'
},
title: {
text: 'Monthly Average Rainfall'
},
subtitle: {
text: 'Source: WorldClimate.com'
},
xAxis: {
categories: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
],
crosshair: true
},
yAxis: {
min: 0,
title: {
text: 'Rainfall (mm)'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [
{
name: 'Dry',
data: dryJson.items.map(i => i.score)
}, {
name: 'Operating',
data: operatingJson.items.map(i => i.reputation / 100)
}]
});
}
async function start() {
var key = '1*tsYg4Q3UbK06qftc8VmQ(('
await createChart('container1', 'https://api.stackexchange.com/2.3/posts?order=desc&sort=votes&pagesize=12&site=stackoverflow&key='+key, 'https://api.stackexchange.com/2.3/users?order=desc&sort=reputation&pagesize=12&site=stackoverflow&key='+key)
}
start()
<script src="https://cdnjs.cloudflare.com/ajax/libs/highcharts/10.3.3/highcharts.js"></script>
<div id="container1">
loading ...
</div>
I am working on Kendo UI jQuery grid CRUD. I can get data display in the grid, but not adding new records.
When I click the update button to add a record after filling up columns in the pop-up window, nothing is posted to the server side as every property has a null value.
The picture shows what I got when the button is pressed.
Controller:
[HttpPost]
public JsonResult AddLostProperty(LostPropertyViewModel lostProperty)
{
try
{
using (var dbContext = new DBEntities())
{
if (lostProperty != null)
{
var newLostProperty = new sz_LostProperty()
{
Name = lostProperty.PropertyName,
CategoryId = dbContext.sz_PropertyCategory.Where(x => x.Name == lostProperty.CategoryName).Select(c => c.Id).FirstOrDefault(),
Description = lostProperty.PropertyDescription,
FoundDate = lostProperty.FoundDate,
FoundLocation = lostProperty.FoundLocation,
CratedDate = DateTime.UtcNow.Date,
CratedBy = ""
};
dbContext.sz_LostProperty.Add(newLostProperty);
dbContext.SaveChanges();
return Json(new { Success = true, Message = "The Property has been added." });
}
else
{
return Json(new { Success = false, Message = "No lost property added." });
}
}
}
catch (Exception e)
{
return Json(new { Success = false, Message = "Error: " + e });
}
}
JavaScript:
<script>
$(document).ready(function () {
var serviceBaseUrl = "#Request.Url.ToString()",
lostPropertyDataSource = new kendo.data.DataSource({
transport: {
create: {
url: serviceBaseUrl + "/AddLostProperty",
type: "POST",
dataType: "json",
complete: function (e) {
$('#manageLostPropertiesGrid').data('kendoGrid').dataSource.read();
}
},
read: {
url: serviceBaseUrl + "/GetLostProperties",
type: "GET",
dataType: "json"
},
update: {
url: serviceBaseUrl + "/UpdateLostProperty",
type: "PUT",
dataType: "json"
},
destroy: {
url: serviceBaseUrl + "/DeleteLostProperty",
type: "DELETE",
dataType: "json"
},
parameterMap: function (options, operation) {
if (operation !== "read" && options.models) {
return { models: kendo.stringify(options.models) };
}
}
},
batch: true,
pageSize: 20,
schema: {
model: {
id: "PropertyId",
fields: {
PropertyId: { editable: false, nullable: true, type: "number" },
PropertyName: { type: "string", editable: true, validation: { required: true } },
CategoryId: { type: "number", editable: true, validation: { required: true } },
PropertyDescription: { validation: { required: false } },
Image: { validation: { required: false } },
FoundDate: { type: "Date" },
FoundLocation: { editable: true, validation: { required: false } }
}
}
}
});
$("#manageLostPropertiesGrid").kendoGrid({
dataSource: lostPropertyDataSource,
pageable: true,
height: 550,
toolbar: ["create"],
columns: [
{ field: "PropertyName", title: "Property Name", width: "150px" },
{ field: "CategoryName", title: "Category", editor: propertyCategoryList,/* template: "#=CategoryName#", */width: "150px"},
{ field: "PropertyDescription", title: "Description", width: "200px" },
{ field: "FoundDate", title: "Found Date", template: "#= kendo.toString(kendo.parseDate(FoundDate, 'dd-MM-yyyy'), 'dd-MM-yyyy') #", width: "130px" },
{ field: "FoundLocation", title: "Found Location", width: "120px" },
{ command: ["edit", "destroy"], title: " ", width: "250px" }],
editable: "popup"
}).data("kendoGrid");
});
From the browser, I can see the object sent to the server below:
What am I doing wrong?
I believe that in this case is problem in your parameter type at server side.
You have enabled batch: true editing which is useful if you want make many changes in your grid but send only one request with changed models in the end. It is very useful for example in case of inCell edit mode, when you would see many many requests and so decrease them is something you want, but in case of popup edit, I personally do not see any reason to use batch editing, but yes, I know Telerik has this in their demo.
So, because batch editing is enabled, there is called parameterMap before request is executed. (note: parameterMap is called only if you have batch edit enabled, otherwise it's ignored). That parameterMap wraps all your models into json string array and send that array with request to the server. In your case, there is always one record edited, but it doesn't matter - it will be sent as an array (in json string format).
Because it is sent as serialized string, you can
1) Change parameter of your AddLostProperty method to string models and then deserialize into array which allows you to work with it as you are used to
public ActionResult AddLostProperty(string models)
{
...
var data = JsonConvert.DeserializeObject<IEnumerable<LostPropertyViewModel>>(models);
...
}
2) If we will follow Telerik demo, you can use such implementation
public ActionResult AddLostProperty()
{
var products = this.DeserializeObject<IEnumerable<LostPropertyViewModel>>("models");
if (products != null)
{
//logic
}
return this.Jsonp(products);
}
3) And this is solution I would prefer
Just remove batch: true and parameterMap (since without batch it's useless) - and it should start send single object to your server method.
In order to make a real-time .NET Web application, I am using SignalR for Kendo grid, which works with read, update, destroy method on the grid.
However, my situation is creating and updating records from other pages, the Kendo Grid just for reading data. I would like to implement SignalR to notify user whenever a new record is added to the database.
Here is my code.
SignalRHub class:
public class SignalRHub : Hub
{
private DbEntities db;
public SignalRHub()
{
db = new DbEntities();
}
public IEnumerable<ViewTicketModel> Read()
{
return db.Post_User.AsEnumerable()
.Select(ticket => new ViewTicketModel
{
Id = ticket.Id,
BuyerName = ticket.Name,
DateCreated = ticket.CreatedOn.ToString("dd/MM/yyyy"),
BuyerPhoneNumber = ticket.Mobile,
Details = ticket.Details,
Location = ticket.Location,
})
.OrderByDescending(x => DateTime.ParseExact(x.DateCreated, "dd/MM/yyyy", null))
.ToList();
}
}
Index.cshtml:
var connection = $.connection;
var hub = connection.signalRHub;
var hubStart = connection.hub.start();
console.log("here");
var signalRDataSource = new kendo.data.DataSource({
type: "signalr",
autoSync: true,
push: function(e) {
var notification = $("#notification").data("kendoNotification");
notification.success(e.type);
},
schema: {
model: {
id: "Id",
fields: {
"Id": { editable: false, type: "Number" },
"BuyerName": { type: "string" },
"DateCreated": { type: "string" },
"BuyerPhone": { type: "string" },
"Details": { type: "string" },
"Location": { type: "string" }
}
}
},
transport: {
signalr: {
promise: hubStart,
hub: hub,
server: {
read: "read",
},
client: {
read: "read",
}
}
},
pageSize: 10,
});
$("#grid").kendoGrid({
height: 700,
filterable: {
extra: false,
},
pageable: true,
sortable: {
mode: "multiple",
allowUnsort: true
},
columns: [
{ field: "Id", title: "Notification Id", width: 100, hidden: true },
{
field: "DateCreated",
title: "Date Created",
width: 150,
filterable: {
ui: "datetimepicker"
}
},
{ field: "Location", title: "Location", width: 150 },
{ field: "BuyerName", title: "Buyer Name", width: 120, hidden: true },
{ field: "BuyerPhoneNumber", title: "Buyer Phone", width: 120, hidden: true },
],
dataSource: signalRDataSource
});
by other pages, you meant different application? If that is the case, this will complicate the issue.
remember kendo grid only comes with 4 default signal actions (create, update, read, destroy). Any other will have to be implemented by you.
here's an example how you can make your "connected" clients do a refresh read.
in your hub:
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<Dashboard>();
context.Clients.All.reload();
in your client html page:
<script type="text/javascript">
var hub = $.connection.dashboard;
hub.client.reload = function () {
updategrid();
};
var hubStart = $.connection.hub.start();
function updategrid()
{
$('#GridName').data('kendoGrid').dataSource.read();
$('#GridName').data('kendoGrid').refresh();
}</script>
This will force all your connected clients to do a refresh.
The perfect scenario would be to the appropriate changes pushed out to the client. This implementation can get tricky, because you don't know what filter/sort/grouping the user has on their side. However, it's achievable. You can have each connected client to send it's filter/grouping/sort back to the server and pull only the appropriate change.
How do I plot highchart Gauge with JSON Data?
I am working on highchart gauge, I got succes in showing the latest data from the database. I used JavaScriptSerializer for that
The code is..
<script type="text/javascript">
$(function () {
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'gauge',
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false
},
//Other char parameter comes here
}
function (chart) {
setInterval(function () {
$.getJSON("S14.aspx", function (data, textStatus) {
console.log(data);
$.each(data, function (index, wind) {
var point = chart.series[0].points[0],
newVal = wind;
point.update(newVal);
});
});
}, 3000);
});
The code for JSON is
public string chartData1
{
get;
set;
}
protected void Page_Load(object sender, EventArgs e)
{
List<double> _data = new List<double>();
GetData();
foreach (DataRow row in dt.Rows)
{
_data.Add((double)Convert.ToDouble(row["S11"]));
}
JavaScriptSerializer jss = new JavaScriptSerializer();
chartData1 = jss.Serialize(_data);
}
My JSON looks like
[1387204961992.4268,72]
Well the problem is that the dial of gauge is not moving according to the last values i need to refresh the page for that. I know this is happening because the GetData function is being executed only one time. I am stuck here.
How do I get the dial move according to the last values updates in the database?
Try to place this part of code
setInterval(function() {
$(function() {
$.getJSON('S12.aspx', function(data) {
$.each(data, function(val) {
if (val !== null)
{
var point = chart.series[0].points[0];
point.update(val);
}
});
});
})
},2000)
Inside callback chart, like here: http://www.highcharts.com/demo/gauge-speedometer
If you receive any errors,please attach.
I think there is a bug or something in the visual studio 2012 . I just paste the entire code on the new aspx page it it got working. I have not done anything else I just pasted the code on another page.
<script type="text/javascript">
$(function () {
$('#container1').highcharts({
chart: {
type: 'gauge',
alignTicks: false,
plotBackgroundColor: null,
plotBackgroundImage: null,
plotBorderWidth: 0,
plotShadow: false
},
title: {
text: 'Pressure Meter'
},
pane: {
startAngle: -150,
endAngle: 150
},
yAxis: [{
min: 0,
max: 1000,
lineColor: '#339',
tickColor: '#339',
minorTickColor: '#339',
offset: -25,
lineWidth: 2,
labels: {
distance: -20,
rotation: 'auto'
},
tickLength: 5,
minorTickLength: 5,
endOnTick: false
}, {
min: 0,
max: 1000,
tickPosition: 'outside',
lineColor: '#933',
lineWidth: 2,
minorTickPosition: 'outside',
tickColor: '#933',
minorTickColor: '#933',
tickLength: 5,
minorTickLength: 5,
labels: {
distance: 12,
rotation: 'auto'
},
offset: -20,
endOnTick: false
}],
series: [{
name: 'Pressure',
data: [80],
dataLabels: {
formatter: function () {
var psi = this.y,
bar = Math.round(psi / 14.50);
return '<span style="color:#339">' + psi + ' psi</span><br/>' +
'<span style="color:#933">' + bar + ' bar</span>';
},
backgroundColor: {
linearGradient: {
x1: 0,
y1: 0,
x2: 0,
y2: 1
},
stops: [
[0, '#DDD'],
[1, '#FFF']
]
}
},
tooltip: {
valueSuffix: ' psi'
}
}]
},
// Add some life
function (chart) {
setInterval(function () {
$.getJSON("S12.aspx", function (data, textStatus) {
$.each(data, function (index, wind) {
var point = chart.series[0].points[0],
newVal = wind;
point.update(newVal);
});
});
}, 3000);
});
});
</script>
In order for the chart to update, the browser somehow needs to request the latest data from the server. There are two ways it can do this:
A page refresh - the whole page is fetched again, with the latest data.
An Ajax request. This makes a request for just the data, without re-loading the entire page.
I presume you would like to update the chart without reloading the entire page. In order do to this, you need to find out about making ajax requests using jquery.
The highcharts site has some resources which will help you (e.g. http://www.highcharts.com/docs/working-with-data/preprocessing-live-data). You need to learn how to make an ajax call in javascript, and use the returned data to update your chart. You will also need to write the server side part which returns the ajax data. The example given is in php, but it should be fairly straight forward to do something similar in asp.net.
I have 4 grid tables. They use the same modal. I cannot use the same store as each grid has to send a parameter value to get the data from db. So, what's happening is I ended up making 4 different stores and then when I load my application, it lags because it waits to load all the 4 stores. this is my grid.. so I have 3 more grids like this
this.grid1 =Ext.create('Ext.grid.Panel',{
title:'GridView App', store: store, loadMask:true,
columns:[
{ header:'Q1', sortable:true, dataIndex:'Q1', flex:1,},
{ header:'Q2', sortable:true, dataIndex:'Q2', flex:1,},
{ header:'Q3', sortable:true, dataIndex:'Q3', flex:1,},
{ header:'Q4', sortable:true, dataIndex:'Q4', flex:1,}
and this is my store1... and similarly I have 3 more stores like this each with parameter Q2, Q3, Q4 respectively
var store1 =Ext.create('Ext.data.JsonStore',{
storeId:'myData', scope:this,
fields:[
{ name:'Q1', type:'int'},
{ name:'Q2', type:'int'},
{ name:'Q3', type:'int'},
{ name:'Q4', type:'int'}
],
sorters:[{ property:'Q1', direct:'ASC'}],
proxy:{
type:'ajax',
url:'GridView/writeRecord',
extraParams: { ID: Q1 },
reader: newExt.data.JsonReader({
root:'myTable',
totalProperty:'count'
})
}
});
Is there a faster/better way to implement it than the way that I have?
UPDATE -
SECOND UPDATE -
Here is my layout for the whole application... my rightcontainer is disabled at first and contains the actual grids and forms, and click on the item on tab enables the rightcontainer and loads all the grid.
Ext.define('ExtjsApp.app1.appPanel', {
extend: 'Ext.panel.Panel',
alias: 'widget.mypanel',
layout: {
type: 'vbox',
align: 'stretch'
},
scope: this,
titleAlign: 'center',
minWidth: 900,
bodyPadding: 10,
requires: [],
items: [],
constructor: function () {
this.callParent(arguments);
this.regForm = Ext.create('ExtjsApp.app1.RegForm', {});
leftTreeStore = Ext.create('Ext.data.TreeStore', {
scope: this,
storeId: 'leftTreeStore',
fields: [
{ name: 'text', type: 'string' },
{ name: 'dataId', type: 'string' },
{ name: 'listName', type: 'string' },
{ name: 'leaf', type: 'bool' }
],
root: { expanded: true },
proxy: {
type: 'ajax',
url: 'app1/getRecords',
extraParams: { organization: 'GOOGLE' },
reader: { type: 'json' }
},
autoLoad: true,
expanded: true,
autoSync: true,
listeners: {
}
});
allRecordsStore = Ext.create('Ext.data.TreeStore', {
id: 'allRecordsStore',
autoLoad: false,
autoSync: false,
scope: this,
fields: [
{ name: 'text', type: 'string' },
{ name: 'dataId', type: 'string' },
{ name: 'listName', type: 'string' },
{ name: 'leaf', type: 'bool' }
],
root: { expanded: true },
proxy: {
type: 'ajax',
url: 'app1/getRecords',
extraParams: { organization: 'GOOGLE' },
reader: { type: 'json' }
}
});
this.currentMonthsTree = Ext.create('Ext.tree.TreePanel', {
scope: this,
title: 'Current 12 Months',
titleAlign: 'center',
tabIndex: 0,
height: 500,
flex: 1,
rootVisible: false,
store: leftTreeStore,
id: 'currentMonthsTree',
useArrows: true,
hideHeaders: true,
columns: [
{
xtype: 'treecolumn',
id: 'ID',
dataIndex: 'text',
flex: 1
}
],
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
enableDrop: false,
appendOnly: false,
enableDrag: false
},
listeners: {
itemclick: function (view, rec, item) {
if (rec.isLeaf()) {
alert('isLeaf');
}
else if (!rec.isLeaf()) {
alert('isNotLeaf');
}
}
},
allowCopy: true,
copy: true
}
});
this.currentMonthsTree.on('selectionchange', function (selected) {
FnDisplayRecord(selected.selected.items[0]);
});
this.allRecordsTree = Ext.create('Ext.tree.TreePanel', {
scope: this,
title: 'All Records',
titleAlign: 'center',
flex: 1,
tabIndex: 1,
rootVisible: false,
store: allRecordsStore,
id: 'allRecordsTree',
useArrows: true,
hideHeaders: true,
columns: [
{
xtype: 'treecolumn',
id: 'ID',
dataIndex: 'text',
flex: 1
}
],
viewConfig: {
plugins: {
ptype: 'treeviewdragdrop',
enableDrop: false,
enableDrag: false,
appendOnly: false
},
listeners: {
itemclick: function (view, rec, item) {
if (rec.isLeaf()) {
alert('isLeaf');
}
else if (!rec.isLeaf()) {
alert('isNotLeaf');
}
}
},
allowCopy: true,
copy: true
}
});
this.allRecordsTree.on('selectionchange', function (selected) {
FnDisplayRecord(selected.selected.items[0]);
//alert('Hello');
});
function FnClearValues() {
//Clear All Values
alert('ClearALLValues');
}
function FnSetValues(myObj) {
//I set all my form values using Ext.getCmp
Ext.getCmp('Textl').setValue(myObj.Text1);
}
function FnDisplayRecord(row) {
if (row.get('leaf') == true) {
console.log(row.data.dataId);
var tempID = row.data.dataId;
Ext.getCmp('rightContainer').setLoading(true, true);
Ext.getCmp('requisitionPOGridPanel').store.loadData([], false);
Ext.Ajax.request({
method: 'GET',
url: 'app1/getRecord',
headers: { 'Content-Type': 'application/json' },
dataType: 'json',
params: {
ID: tempID
},
success: function (response) {
Ext.getCmp('rightContainer').setLoading(false, false);
myObj = Ext.JSON.decode(response.responseText);
if (AsbestosObj.DateIssued != '') {
FnSetValues(AsbestosObj);
Ext.getCmp('GridPanel').store.load({ params: { ID: tempID} });
Ext.getCmp('Grid1').store.load({ params: { ID: tempID, qID: 'Q01'} });
Ext.getCmp('Grid2').store.load({ params: { ID: tempID, qID: 'Q02'} });
Ext.getCmp('Grid3').store.load({ params: { ID: tempID, qID: 'Q03'} });
Ext.getCmp('Grid4').store.load({ params: { ID: tempID, qID: 'Q04'} });
}
else { FnClearValues(); }
},
failure: function () {
Ext.Msg.alert('Message', 'Error');
}
});
}
else if (row.get('leaf') == false) {
FnClearValues();
}
}
this.rightContainer = Ext.create('Ext.form.Panel', {
scope: this,
id: 'rightContainer',
layout: {
type: 'vbox',
align: 'stretch',
pack: 'start'
},
autoScroll: true,
disabled: true,
border: 1,
flex: 1,
items: [
this.regForm
]
});
this.tabContainer = Ext.create('Ext.tab.Panel', {
scope: this,
activeTab: 0,
flex: 0.5,
id: 'tabContainer',
layout: { type: 'vbox', align: 'stretch' },
plain: true,
listeners: {
tabchange: function (panel, newTab, oldTab) {
Ext.getCmp('rightContainer').disable();
FnClearValues();
var getTabStat = this.getActiveTab();
if (getTabStat.tabIndex == 0) {
Ext.getCmp('currentMonthsTree').store.load();
}
else if (getTabStat.tabIndex == 1) {
Ext.getCmp('allRecordsTree').store.load();
}
}
},
items: [
this.currentMonthsTree, this.allRecordsTree
]
});
this.mainContainer = Ext.create('Ext.container.Container', {
scope: this,
bodyPadding: 10,
title: 'MAIN',
layout: {
type: 'hbox',
align: 'stretch'
},
flex: 1,
items: [
this.tabContainer,
{ xtype: 'splitter', width: 5, animate: true },
this.rightContainer
]
});
this.add(this.mainContainer);
},
loadingOn: function () {
setTimeout(function () { Ext.getCmp('currentMonthsTree').setLoading(true, true); }, 100);
},
loadingOff: function () {
setTimeout(function () { Ext.getCmp('currentMonthsTree').setLoading(false, false); }, 100);
}
});
Please reference my SO question that is very similar: Combo box loads too slow
Basically, you will want to define all your models as you do normally.
Then you will want to define all the stores for your page as array stores without proxies, like this:
var myStore1 = Ext.create("Ext.data.ArrayStore", {
model: "MyModel1",
data: []
});
var myStore2 = Ext.create("Ext.data.ArrayStore", {
model: "MyModel1",
data: []
});
Then you will want to create a single call to wherever you are getting your data from, you will need to change the server to output all the arrays into an single JSON object, something like this, and for super optimization, make them array arrays, this would be the output I would expect from the server:
{
grid_data_1: [...],
grid_data_2: [...]
}
Then on your webpage after you create all the stores, make a single ajax call to get the data for all four grids:
Ext.Ajax.request({
url: 'url',
method: 'GET',
params: {
...whatever you want
},
success: function (response, opts) {
var result = Ext.decode(response.responseText);
myStore1.loadData(result.grid_data_1);
myStore2.loadData(result.grid_data_2);
...
},
});
This will make it much more efficient, you probably don't need to use array arrays in your case because there is only 5 rows per grid, but optimizing 4 ajax calls into one should have a large impact.
You cannot do much more here. I think you can do some micro tunes but I doubt they are worth time they took to identify. If your app do the following you've done it all the right way;
Time till your is loaded
Init only the required controller and the stores (check each request)
Show the main view
As soon as your grids get rendered they will fire the load operation, at least when they have a paging toolbar. You could begin the load operation earlier, meaning before you create the view that may give you some milliseconds but I doubt that you can save more time.
This is of course based on the available information's.