I'm having a table whose contents(name and status) i'm trying to refresh every 1 min in such a way that the status should change from 'schedule' to 'active' to 'running' w/o having user manually refresh it.
here is the js:
$cls.superclass.constructor.call(this, Ext.apply({
useTemplate: true,
directFn: Service('getRecordService').getRecord,
fields: [
{
name : 'name',
column: {
header: "Name",
renderer: function (record) {
return name(record.data.name);
},
}
},
{
name : 'status',
column: {
header: "status",
renderer: function (record) {
return status(record.data.status);
},
}
},
],
viewConfig: {
getRecord: function (){
///get single record info
}
};
});
I'm not sure how can i write a function in the above snippet that will allow me to auto refresh the table contents every 1 min. Any ideas would be appreciated!
Thanks!
You should take a look at Ext.util.TaskRunner and the singleton Ext.TaskMgr.
It provides methods to start/stop task functions which are executed in a configurable interval.
With that you could try something like below.
var grid = ; // your grid instance
var store = grid.getStore(); // store of your grid, you want to reload
var refreshTask = { // task which reloads the store each minute
run: function() {
store.reload();
},
interval: 60 * 1000 // 1 Minute
};
Ext.util.TaskRunner.start(refreshTask);
Related
I have been trying to figure out what is going on but haven't yet.
Please see the code below.It is a inconsistent behavior, so I am having hard time to catch what triggers it. This grid is inside a popup, I noticed when i refresh the page and try it, it works fine on first attempt. Then i save/cancel popup and keep repeating it fails at some point and starts accumulate null rows.
I tried to check the value of the grid using
$('#gridFldListItems').data("kendoGrid").dataSource.data()
It shows there is no data but as soon as click "Add new Record" it shows 2.
It does not necessarily fail on second attempt, but it never fails on first. I suspect that everytime I open the popup it is not necessarily empty(after first few tries) and it carries some data from previous attempts. I might be wrong.
When I click add new record, it adds a line with null value and gives me an option to input on the second row.
I also When I put itemname and click update, it does not trigger the "create" event and looks like this:
At this point the grid broken. Here is the code for the grid
var grid = $("#gridFldListItems").kendoGrid({
editable: {
"confirmation": "Are you sure you want to delete this item?",
"mode": "inline",
"createAt": "bottom"
},
selectable: true,
autoBind: false,
toolbar: ["create" ],
columns: [
{ field: 'Item' },
{
command: ['edit', 'destroy',
{ iconClass: "k-icon k-i-arrow-up", click: $.proxy(this, 'selectedFieldDef_onClkMoveUp'), name: 'Up' },
{ iconClass: "k-icon k-i-arrow-down", click: $.proxy(this, 'selectedFieldDef_onClkMoveDown'), name: 'Down' }], title: ' '
}
],
dataSource: this.selectedFieldDef_dsItems,
}).data("kendoGrid");
selectedFieldDef_dsItems: new kendo.data.DataSource({
transport: {
read: function (e) {
var field = editViewModel.get("selectedFieldDef");
var mapItems = $.map(field.Items, function (item, idx) {
return {
Item: item
};
});
//on success
e.success(mapItems);
},
create: function (e) {
// on success
e.success(e.data);
},
update: function (e) {
// on success
e.success();
},
destroy: function (e) {
var vm = editViewModel;
// locate item in original datasource and remove it
var field = vm.get("selectedFieldDef");
if (field.DefaultValue && !vm.selectedFieldDef_dsItemsFindItem(vm.selectedFieldDef_dsItems.data(), field.DefaultValue)) {
field.DefaultValue = null;
vm.set("selectedFieldDef", field);
$("#inpFldRegex").kendoDropDownList().data("kendoDropDownList").trigger("change");
}
// on success
e.success();
}
},
error: function (e) {
alert("Status: " + e.status + "; Error message: " + e.errorThrown);
},
schema: {
model: {
id: "Item",
fields: {
Item: { editable: true, nullable: true }
}
}
}
})
Any help would be much appreciated.
UPDATE:
It works fine when I refresh the page
I have a grid with thousands of records. It works almost fine. When I programmatically call this method:
selectionModel.selectAll(true);
it works great. My script is not freezed, because of this true parameter, which according to docs suppresses any select events. However, when I select all records via a header checkbox (which selects and deselects all records), my script gets freezed. I guess, it is because by default select events are not suppressed. I tried to find a config, which globally supresses select events, but could not find it. So, my question is how can I fix this issue? How can I globally suppress select events in my grid selModel?
You can handle using overriding onHeaderClick method of grid CheckboxModel.
In this Fiddle, I have created a demo using same method onHeaderClick.
CODE SNIPPET
Ext.application({
name: 'Fiddle',
launch: function () {
var store = Ext.create('Ext.data.Store', {
fields: ['number'],
data: (() => {
let data = [];
for (let i = 1; i <= 50000; i++) {
data.push({
'number': i
})
}
return data;
})()
});
Ext.create('Ext.grid.Panel', {
title: 'Demo',
store: store,
itemId: 'demogrid',
columns: [{
text: 'Number',
flex: 1,
dataIndex: 'number'
}],
height: window.innerHeight,
renderTo: Ext.getBody(),
selModel: {
checkOnly: false,
mode: 'SIMPLE',
onHeaderClick: function (headerCt, header, e) {
var me = this,
store = me.store,
isChecked, records, i, len,
selections, selection;
if (me.showHeaderCheckbox !== false && header === me.column && me.mode !== 'SINGLE') {
e.stopEvent();
isChecked = header.el.hasCls(Ext.baseCSSPrefix + 'grid-hd-checker-on');
if (isChecked) {
console.time();
me.deselectAll(true);
console.timeEnd();
} else {
console.time();
me.selectAll(true);
console.timeEnd();
}
}
}
},
selType: 'checkboxmodel',
buttons: [{
text: 'Select All',
handler: function (btn) {
var grid = btn.up('#demogrid');
console.time();
grid.getSelectionModel().selectAll(true);
console.timeEnd();
}
}, {
text: 'Deselect All',
handler: function (btn) {
var grid = btn.up('#demogrid');
console.time()
grid.getSelectionModel().deselectAll(true);
console.timeEnd();
}
}]
});
}
});
use suspendEvents function on model to stop all events and after you done you can start all events by resumeEvents
grid.getSelectionModel().suspendEvents();
grid.getSelectionModel().resumeEvents();
I am in the process of learning Backbone.js and using BackGrid to render data and provide the end user a way to edit records on an Microsoft MVC website. For the purposes of this test grid I am using a Vendor model. The BackGrid makes the data editable by default (which is good for my purpose). I have added the following JavaScript to my view.
var Vendor = Backbone.Model.extend({
initialize: function () {
Backbone.Model.prototype.initialize.apply(this, arguments);
this.on("change", function (model, options) {
if (options && options.save === false) return;
model.url = "/Vendor/BackGridSave";
model.save();
});
}
});
var PageableVendors = Backbone.PageableCollection.extend(
{
model: Vendor,
url: "/Vendor/IndexJson",
state: {
pageSize: 3
},
mode: "client" // page entirely on the client side.
});
var pageableVendors = new PageableVendors();
//{ data: "ID" },
//{ data: "ClientID" },
//{ data: "CarrierID" },
//{ data: "Number" },
//{ data: "Name" },
//{ data: "IsActive" }
var columns = [
{
name: "ID", // The key of the model attribute
label: "ID", // The name to display in the header
editable: false, // By default every cell in a column is editable, but *ID* shouldn't be
// Defines a cell type, and ID is displayed as an integer without the ',' separating 1000s.
cell: Backgrid.IntegerCell.extend({
orderSeparator: ''
})
}, {
name: "ClientID",
label: "ClientID",
cell: "integer" // An integer cell is a number cell that displays humanized integers
}, {
name: "CarrierID",
label: "CarrierID",
cell: "number" // A cell type for floating point value, defaults to have a precision 2 decimal numbers
}, {
name: "Number",
label: "Number",
cell: "string"
}, {
name: "Name",
label: "Name",
cell: "string"
},
{
name: "IsActive",
label: "IsActive",
cell: "boolean"
}
];
// initialize a new grid instance.
var pageableGrid = new Backgrid.Grid({
columns: [
{
name:"",
cell: "select-row",
headercell: "select-all"
}].concat(columns),
collection: pageableVendors
});
// render the grid.
var $p = $("#vendor-grid").append(pageableGrid.render().el);
// Initialize the paginator
var paginator = new Backgrid.Extension.Paginator({
collection: pageableVendors
});
// Render the paginator
$p.after(paginator.render().el);
// Initialize a client-side filter to filter on the client
// mode pageable collection's cache.
var filter = new Backgrid.Extension.ClientSideFilter({
collection: pageableVendors,
fields: ['Name']
});
// REnder the filter.
$p.before(filter.render().el);
//Add some space to the filter and move it to teh right.
$(filter.el).css({ float: "right", margin: "20px" });
// Fetch some data
pageableVendors.fetch({ reset: true });
#{
ViewBag.Title = "BackGridIndex";
}
<h2>BackGridIndex</h2>
<div id="vendor-grid"></div>
#section styles {
#Styles.Render("~/Scripts/backgrid.css")
#Styles.Render("~/Scripts/backgrid-select-all.min.css")
#Styles.Render("~/Scripts/backgrid-filter.min.css")
#Styles.Render("~/Scripts/backgrid-paginator.min.css")
}
#section scripts {
#Scripts.Render("~/Scripts/underscore.min.js")
#Scripts.Render("~/Scripts/backbone.min.js")
#Scripts.Render("~/Scripts/backgrid.js")
#Scripts.Render("~/Scripts/backgrid-select-all.min.js")
#Scripts.Render("~/Scripts/backbone.paginator.min.js")
#Scripts.Render("~/Scripts/backgrid-paginator.min.js")
#Scripts.Render("~/Scripts/backgrid-filter.min.js")
#Scripts.Render("~/Scripts/Robbys/BackGridIndex.js")
}
When the user edits a row, it successfully fires the hits the model.Save() method and passes the model to the save Action, in this case BackGridSave and it successfully saves the record that changed, but seems to save all of the vendors in model when only one of the vendors changed. Is there a way from the JavaScript/Backbone.js/BackGrid to only pass one Vendor - the vendor that changed?
Update: I realized that it is not sending every vendor, but it is sending the same vendor multiple times as though the change event was firing multiple times.
I guess I answered my own question. Well, at least I am getting the desired result. I just added a call to off after the first on. Seems like this would not be necessary though.
var Vendor = Backbone.Model.extend({
initialize: function () {
Backbone.Model.prototype.initialize.apply(this, arguments);
this.on("change", function (model, options) {
if (options && options.save === false) return;
model.url = "/Robbys/BackGridSave";
model.save();
model.off("change", null, this); // prevent the change event from being triggered many times.
});
}
});
I've created my first ng-grid table and loading it with data asynchronously from the server. All my code seems to get executed created and function as desired behind the scenes except for one major problem.
ng-grid's pagination buttons get rendered in HTML as 'button' tags like this:
<button class="ngPagerButton" ng-click="pageForward()" ng-disabled="cantPageForward()" title="Next Page">
<div class="ngPagerLastTriangle ngPagerNextTriangle"></div>
</button>
But there is no type attribute put on the button so it defaults to type='submit'.
Whenever I click on the next page button, behind the scenes everything works, but it also does an extraneous POST because of the button type. This is completely undesired.
Anyone else run into this? How do you get around it? Am I doing something wrong?
The basic setup is as follows:
HTML:
<div id='deposits' class='gridStyle' ng-grid='gridOptions'></div>
JS controller code (really nothing special here, taken pretty much right from the ng-grid docs...but not working!):
$scope.reportingForm = {
startDate: new Date(2014, 1, 1), // just for testing
endDate: new Date(2014, 1, 7),
};
$scope.filterOptions = {
filterText: '',
useExternalFilter: true
};
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [7, 14],
pageSize: 7,
currentPage: 1
};
$scope.setPagingData = function(data, page, pageSize) {
var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
$scope.data = pagedData;
$scope.totalServerItems = data.length;
if (!$scope.$$phase) {
$scope.$apply();
}
};
$scope.getPagedDataAsync = function(pageSize, page, searchText) {
setTimeout(function () {
var data;
if (searchText) {
var filter = searchText.toLowerCase();
myService.getDataAsync(
$scope.reportingForm.startDate, $scope.reportingForm.endDate
function(result) {
data = result.result.data.filter(function(item) {
return JSON.stringify(item).toLowerCase().indexOf(filter) != -1;
});
$scope.setPagingData(data, page, pageSize);
}
);
} else {
myService.getDataAsync(
$scope.reportingForm.startDate, $scope.reportingForm.endDate,
function(result) {
$scope.setPagingData(result.result.data, page, pageSize);
}
);
}
}, 100);
};
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
}
}, true);
$scope.$watch('filterOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
}
}, true);
$scope.gridOptions = {
data: 'data',
pagingOptions: $scope.pagingOptions,
filterOptions: $scope.filterOptions,
enablePaging: true,
showFooter: true,
columnDefs: [
{ field: 'date', displayName: 'Date' },
{ field: 'id', displayName: 'Id' },
{ field: 'location', displayName: 'Location' },
{ field: 'amount', displayName: 'Amount' },
]
};
ng-grid renders the previous and next page buttons as <button> and does not specify a button type so it defaults to type='submit'.
In our page the ng-grid table lived within a form. I didn't know this but after some testing realized submit <button>s within a form do a POST, but submit <button>s outside of a form do NOT do a POST.
By moving our ng-grid table outside of the form we no longer have this problem.
Really though, this seems to be an oversight in the ng-grid code. It should really be rendering the buttons as type='button' to prevent this kind of issue in the future. I can't imagine any cases where you'd want the last/next page buttons to do POSTs.
This appears to have been fixed in ng-grid 2.0.8 whenever it is released.
https://github.com/angular-ui/ng-grid/pull/693
I've set up my kendo ui grid to read data from an MVC action that returns JSON. I'm using the free version of Kendo and not the MVC specific, due to cost.
The issue is that when the page loads and does the initial population of the grid it doesn't show the loading spinner. After grid is populated and I go to another page or sort a column it shows up.
If I set the height parameter of the grid, I get the initial spinner but the grid only shows one row (should have shown 20).
Does anyone know why you have to set the height parameter? Or any way of getting the spinner to work without setting the height.
My kendo javascript kode:
$("#grid").kendoGrid({
dataSource: new kendo.data.DataSource({
transport: {
read: url,
parameterMap: function (options) {
var result = {
pageSize: options.pageSize,
skip: options.skip,
take: options.take,
page: options.page,
};
if (options.sort) {
for (var i = 0; i < options.sort.length; i++) {
result["sort[" + i + "].field"] = options.sort[i].field;
result["sort[" + i + "].dir"] = options.sort[i].dir;
}
}
return result;
}
},
requestStart: function () {
//kendo.ui.progress($("#loading"), true); <-- this works on initial load, but gives two spinners on every page or sort change
},
requestEnd: function () {
//kendo.ui.progress($("#loading"), false);
},
pageSize: 20,
serverPaging: true,
serverSorting: true,
schema: {
total: "total",
data: "data"
},
}),
height: "100%", <-- I want to avoid this as it renders the grid way to small
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
columns: [
{
field: "PaymentRefId",
title: "Id"
},
{
field: "DueDate",
title: "Due Date"
},
{
field: "Credit",
title: "Amount"
},
{
field: "InvoiceGroupId",
title: " ",
sortable: false,
template: 'See details'
}
],
});
I had this same issue. It actually is rendering the spinner / progress bar, but because the grid content area initially has no height, you can't see it. This worked for me. Give it a shot:
// This forces the grids to have just al little height before the initial data is loaded.
// Without this the loading progress bar / spinner won't be shown.
.k-grid-content {
min-height: 200px;
}
The solution var to use a variable to tell me if the dataset load was the initial one or not. It's not a perfect solution, but it's the only one I've been able to make work.
var initialLoad = true;
$("#grid").kendoGrid({
sortable: true,
pageable: {
refresh: true,
pageSizes: true,
buttonCount: 5
},
columns: [
{
field: "PaymentRefId",
title: "Id"
},
{
field: "DueDate",
title: "Due Date"
},
{
field: "Credit",
title: "Amount"
},
{
field: "InvoiceGroupId",
title: " ",
sortable: false,
template: 'See details'
}
],
});
var ds = new kendo.data.DataSource({
transport: {
read: url,
parameterMap: function (options) {
var result = {
pageSize: options.pageSize,
skip: options.skip,
take: options.take,
page: options.page,
};
if (options.sort) {
for (var i = 0; i < options.sort.length; i++) {
result["sort[" + i + "].field"] = options.sort[i].field;
result["sort[" + i + "].dir"] = options.sort[i].dir;
}
}
return result;
}
},
requestStart: function () {
if (initialLoad) <-- if it's the initial load, manually start the spinner
kendo.ui.progress($("#invoiceGroupGrid"), true);
},
requestEnd: function () {
if(initialLoad)
kendo.ui.progress($("#invoiceGroupGrid"), false);
initialLoad = false; <-- make sure the spinner doesn't fire again (that would produce two spinners instead of one)
},
pageSize: 20,
serverPaging: true,
serverSorting: true,
schema: {
total: "total",
data: "data"
},
});
Chances are, because you are creating and setting the datasource in the grid's initialization, the grid loads so fast that you don't see a load spinner. If you look at all the web demos for kendogrid on their website, you rarely see the initial load spinner. On large remote datasources that take longer to load, you would see it.
If I set the height parameter of the grid, I get the initial spinner but the grid only shows one row (should have shown 20)
It's not that it only shows one row. It's because it failed to read it your height property value so it defaulted to as small as possible. Height takes in a numeric pixel value and does not accept percentages. It couldn't read your value, so it probably took longer to initialize the grid, which allowed you to see the load spinner. Instead, height should be set like height: 400, for example. But this is besides the point.
If you really want the user to see a load spinner on start, try loading the datasource outside of the grid initialization. Basically, load the grid first, and load the datasource after so that there is slightly more delay between the grid rendering and datasource setting.
$("#grid").kendoGrid({
//kendoGrid details... but exclude dataSource
});
var ds = new kendo.data.DataSource({
//DataSource details...
});
And then set the datasource like this:
var grid = $("#grid").data("kendoGrid");
grid.setDataSource(ds);
grid.refresh();
However, I think this would still load pretty fast.
Another last resort if you still really want the spinner is to trick the user into thinking it's taking longer to load and manually call the load spinner like you've tried. Call kendo.ui.progress($("#loading"), true);, execute a small delay function for say 250ms and then turn the load spinner off, and then call grid.setDataSource(ds); and refresh.