set total items manually in kendo grid - kendo-ui

I'm using kendo ui grid with paging. I want to set local data (let's say 10 items) and set total number of items manually (to let's say 100) and can't find how to do it.

I think you should be able to do this by setting the schema.total on your DataSource.
Something like:
var myData = [...];
var determineTotal = function () {
return myData.length; // or whatever value you want for the total.
};
var ds = new kendo.data.DataSource({
data: myData,
schema: {
total: determineTotal
}
});
$("#grid").kendoGrid({
dataSource: ds
});

we can set total number of items manually using datasource object
DataSource.total = function (){
return 250
}

Related

How to programmatically create a new row and put that row in edit mode in Kendo grid

In my Kendo grid I am trying to put the 'create new item' button in the header (title) of the command column instead of the toolbar. Here is part of my grid definition:
var grid = $("#grid").kendoGrid({
columns: [{ command: { name: "edit", title: "Edit", text: { edit: "", cancel: "", update: "" } },
headerTemplate: "<a onclick ='NewItemClick()' class='k-button k-button-icontext k-create-alert' id='new-item-button' title='Click to add a new item'><div>New Item</div></a>"},
My question is: how to create a new row and put that row in edit mode in 'NewItemClick()'
There are some troublesome scope issues when you try to bind the click event in the template definition itself.
Instead, it is easier to assign the link an ID, and then bind the click event later. Notice that I've given it id=create.
headerTemplate: "<a id='create' class='k-button k-button-icontext k-create-alert' id='new-item-button' title='Click to add a new item'><div>New Item</div></a>"
Then in document ready, I bind the click event:
$("#create").click(function () {
var grid = $("#grid").data("kendoGrid");
if (grid) {
//this logic creates a new item in the datasource/datagrid
var dataSource = grid.dataSource;
var total = dataSource.data().length;
dataSource.insert(total, {});
dataSource.page(dataSource.totalPages());
grid.editRow(grid.tbody.children().last());
}
});
The above function creates a new row at the bottom of the grid by manipulating the datasource. Then it treats the new row as a row "edit". The action to create a new row was borrowed from OnaBai's answer here.
Here is a working jsfiddle, hope it helps.
I would like to complete on gisitgo's answer. If your datasource takes some time to update, when calling page(...), then the refresh of the grid will cancel the editor's popup. This is averted by binding the call to editRow to the "change" event :
var grid = $("#grid").data("kendoGrid");
if (grid) {
//this logic creates a new item in the datasource/datagrid
var dataSource = grid.dataSource;
var total = dataSource.data().length;
dataSource.insert(total, {});
dataSource.one("change", function () {
grid.editRow(grid.tbody.children().last());
});
dataSource.page(dataSource.totalPages());
}
NB: This approach will yield problems if your grid is sorted because the new row will not necessarily be at the end
I have found that issues might appear if you have multiple pages, such as the inserted row not opening up for edit.
Here is some code based on the current index of the copied row.
We also edit the row based on UID for more accuracy.
function cloneRow(e) {
var grid = $("#grid").data("kendoGrid");
var row = grid.select();
if (row && row.length == 1) {
var data = grid.dataItem(row);
var indexInArray = $.map(grid.dataSource._data, function (obj, index)
{
if (obj.uid == data.uid)
{
return index;
}
});
var newRowDataItem = grid.dataSource.insert(indexInArray, {
CustomerId: 0,
CustomerName: null,
dirty: true
});
var newGridRow = grid.tbody.find("tr[data-uid='" + newRowDataItem.uid + "']");
grid.select(newGridRow);
grid.editRow(newGridRow);
//grid.editRow($("table[role='grid'] tbody tr:eq(0)"));
} else {
alert("Please select a row");
}
return false;
}

Kendo Grid not updating display correctly

I'm working on an application where we are using local storage as our data store based on sample from Kendo Code Library. We are currently planning on using functions in the datasource to manipulate the data. You can see that part of our code below.
I have a working sample at http://jsfiddle.net/photo_tom/fL5UC/2/.
var dataSource = new kendo.data.DataSource({
transport: {
create: function (options) {
var localData = JSON.parse(localStorage["grid_data"]);
localData.push(options.data);
localStorage["grid_data"] = JSON.stringify(localData);
options.success(localData);
},
read: function (options) {
var localData = JSON.parse(localStorage["grid_data"]);
options.success(localData);
},
update: function (options) {
var localData = JSON.parse(localStorage["grid_data"]);
for (var i = 0; i < localData.length; i++) {
if (localData[i].ID == options.data.ID) {
localData[i].Value = options.data.Value;
}
}
localStorage["grid_data"] = JSON.stringify(localData);
options.success(localData);
console.log("On update");
console.log(localData);
},
destroy: function (options) {
var localData = JSON.parse(localStorage["grid_data"]);
localData.remove(options.data.ID);
localStorage["grid_data"] = JSON.stringify(localData);
options.success(localData);
}
To see the problem:
Click on "Add New Record". A new record will appear as the first record in the grid
Enter a number in ID column and any text in value column.
Click on "Save Changes" button.
What was the original first row, will overwrite the newly added row
If you click on the JSFiddle run button, then the data will correctly display.
I'm new at using these grids and I don't see what is causing the problem.
When adding a new record to the grid, you need to leave the ID field set to its default value (don't let the user edit it), and assign its unique value within the transport's create function, which should then provide just the created record as a parameter to options.success. So something like:
create: function (options) {
options.data.ID = getNextID();
var localData = JSON.parse(localStorage["grid_data"]);
localData.push(options.data);
localStorage["grid_data"] = JSON.stringify(localData);
options.success(options.data);
},
I have updated below demo.
create: function (options) {
var localData = JSON.parse(localStorage["grid_data"]);
localData.push(options.data);
localStorage["grid_data"] = JSON.stringify(localData);
options.success(localData);
console.log("On create");
console.log(localData);
$("#grid").data('kendoGrid').dataSource.read();
}
http://jsfiddle.net/fL5UC/3/
The issue you are having is because you are calling options.success with the entire dataset as a parameter. For create and update, you only need to return the updated object, as in the options.data object.
options.success(options.data);
See updated sample http://jsfiddle.net/photo_tom/fL5UC/2/
No need to call read on the datasource again, just options.success the updated/created object, and it will act properly.

MVVM binding to a Kendo Grid is VERY slow?

I am trying to bind a ViewModel to a Kendo DataSource which in turn is given to a Kendo Grid. Nothing too fancy at this point.
It sort of works but is VERY slow! I have an alert informing me that I have received my json data (700 rows) within 2 seconds but it then takes around 15 seconds to update the viewmodel.
What am I doing wrong?
Thanks
$(document).ready(function () {
// create the viewmodel we use as the source for the list
var viewModel = kendo.observable({
items: [],
total: function () {
return this.get("items").length;
}
});
var dataSource2 = new kendo.data.DataSource({
data: viewModel,
pageSize: 50
});
// create the grid
$("#grid").kendoGrid({
dataSource: dataSource2,
height: 500,
scrollable: {
virtual: true
},
columns: [
{ field: "ID_ORDER", title: "ID", width: 80 },
{ field: "CREATION_DATE", title: "Creation Date" },
{ field: "STATUS", title: "STATUS", width: 80 },
** more columns (around 10) **
]
});
// pass this on to initialise
APPS.View.Orders.Initialise(viewModel);
});
Then in my typescript I am handling the Initialise call where the viewModel is passed in:
module APP.View.Orders {
export var _Scope: string = "Orders";
var _viewModelOrders: any;
export var Initialise = function (viewModelOrders: any) {
_viewModelOrders = viewModelOrders;
var orderdetails = {
userid: APP.Core.userID,
context: "DEAL"
};
// retrieve all orders
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
try {
alert("item count (1): " + mydata.length);
jQuery.each(mydata, function () {
var newItem = this;
_viewModelOrders.items.push(newItem);
});
alert("item count (2): " + _viewModelOrders.items.length);
}
catch (e) {
alert(e.message);
}
});
}
}
Try building the item array and then assign it into the model.
Something like:
// retrieve all orders
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
try {
alert("item count (1): " + mydata.length);
var items = [];
jQuery.each(mydata, function () {
items.push(this);
});
_viewModelOrders.items = items;
alert("item count (2): " + _viewModelOrders.items.length);
}
catch (e) {
alert(e.message);
}
});
You can suspend the observable temporarily by doing the following:
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
try {
var simpleArray = viewModel.items(); // get a reference to the underlying array instance of the observable
jQuery.each(mydata, function () {
items.push(this);
});
viewModel.items.valueHasMutated(); // let the observable know it's underlying data has been updated
}
catch (e) {
alert(e.message);
}
}
Doing the above technique dramatically improves loading times. I have testing this loading a few thousand rows in a reasonable time.
To explain further, this is due to the line:
_viewModelOrders.items.push(newItem);
Each time you push an item into the array, it triggers a change event, which the Grid sees and updates itself. So if you push 700 items in, you are really causing the grid to update the DOM 700 times.
It would be much better to aggregate all the items into an array, then assign the array to the DataSource, with something like:
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
datasource2.data(mydata);

Ext JS 4 - how to create multiple store instances and assign to views? (MVC)

How do you create unique instances of stores and assign them to views (I am ok with creating unique views and/or controllers if that's required)?
A simple use case - I want to open multiple grid's (of the same type) with a list of records from a store in each. Each grid would need to have it's own store instance, because it could have it's own list of records, it's own filtering, etc. etc.
I tried this, but it does not work, my grids do not draw:
var theView = Ext.create('App.view.encounter.List');
theView.title = 'WORC Encounters';
var theStore=Ext.create('App.store.Encounters');
theView.store=theStore;
tabhost.add({title:'WORC',items:theView});
var theView = Ext.create('App.view.encounter.List');
theView.title = 'NC Encounters';
var theStore2=Ext.create('App.store.Encounters');
theView.store=theStore2;
tabhost.add({title:'NC',items:theView});
You need to assign the store when the component is initializing (or before). In the initComponent.
Ext.define('classname', {
extend: 'Ext.grid.Panel',
//...
initComponent: function() {
var me = this;
var theStore = Ext.create('App.store.Encounters');
Ext.apply(me, {
store: theStore
});
me.callParent();
}
//...
});
You could also do it this way:
//Create the store
var theStore = Ext.create('App.store.Encounters');
//Create the view
var theView = Ext.create('App.view.encounter.List', {
store: theStore
});
Edit for you example specific:
var theStore = Ext.create('App.store.Encounters');
var theView = Ext.create('App.view.encounter.List', {
title: 'WORC Encounters',
store: theStore
});
tabhost.add({title:'WORC',items:theView});
var theStore2=Ext.create('App.store.Encounters');
var theView2 = Ext.create('App.view.encounter.List', {
title: 'NC Encounters',
store: theStore2
});
tabhost.add({title:'NC',items:theView2});

Sencha Touch refresh list after data in store has been changed

i want to do the following:
I have a store which gets JSON data from the server. The JSON looks like this:
{"id":"1","name":"Name1","address":"exampleaddress1","lat":"48.366268","lng":"10.892320","distance":"0"},{...}]
My model and store:
Ext.regModel('Filiale', {
fields: ['id', 'name', 'address', 'distance', 'lat', 'lng'],
});
var ListStore = new Ext.data.Store({
model: 'Filiale',
id: 'ListStore',
autoLoad: false,
fields:['name', 'address', 'distance'],
proxy: {
type: 'ajax',
url : 'http://example.com/getSomeJson.php',
reader: {
type: 'json'
}
},
listeners: {
load: function(){
ListStore.each(function(store){
var newData = getDistance(store.data); // this function calculates the distance from currentLocation to the received address
console.log(newData); // i see a object in the console, with the correct calculated distance
console.log(newData.distance); // this shows the old distance which is set to '0' in the databse
//at this point i want to update the received records with the new distance, but the list always shows the old distance
});
}
}
});
I don't understand, why the two console.logs show different values for the distance. Can anyone explain that to me ?
My List:
var listPanel = new Ext.List({
title: 'ListStore',
store: ListStore,
id: 'addresslist',
itemTpl: '<div class="contact">{name}, {address}, {distance}</div>',
rendered: false,
listeners: {
beforerender: function(){
ListStore.load();
}
}
});
my function to calculate the distance:
var getDistance = function(dataset){
navigator.geolocation.getCurrentPosition(function(position){
var start = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
//add current position marker to map
var marker = new google.maps.Marker({
map: mapPanel.map,
position: start
});
var end = new google.maps.LatLng(dataset.lat, dataset.lng);
var service = new google.maps.DirectionsService();
var request = {
origin: start,
destination: end,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
service.route(request, function(result, status){
if (status == google.maps.DirectionsStatus.OK) {
dataset.distance = result.routes[0].legs[0].distance.value / 1000;
}
});
});
return dataset;
};
And as i said, the distance is correctly calculated and the objects gets returned... but i'm unable to update the records in the store or the list...
I don't understand, why the two console.logs show different values for the distance. Can anyone explain that to me ?
Are You using Chrome? Chrome console sometimes has problems with up-to-date console data
And as i said, the distance is correctly calculated and the objects gets returned... but i'm unable to update the records in the store or the list...
Records in the store in Your script are always up-to-date - in JS obejcts are passed by reference, so You don't even have to return newData - store object will be updated automatically
Just after adding some values to store type:
listpanel.refresh()
to load current store to list

Resources