Kendo UI grid databinding using mvvm pattern - kendo-ui

I am new to Kendo UI, i want to bind kendo ui grid using MVVM pattern, and my datasource is sharepoint list. so i am calling sharepoint list data through CSOM javascript code. I tried different solution but nothing seems to working. I have collection of data from sharepoint list.
var divisionListData = [];
//var divisionsViewModel;
var viewModel = kendo.observable({
isVisible: true,
onSave: function (e) {
alert('hi');
kendoConsole.log("event :: save(" + kendo.stringify(e.values, null, 4) + ")");
},
divisions: new kendo.data.DataSource({
// schema: {
data: divisionListData,
schema: {
data: "rows",
model: {
fields:
{
ID: { type: "string" },
DivisionName: { type: "string" },
DivisionCode: { type: "string" },
OpenDate: { type: "datetime" },
CloseDate: { type: "datetime" },
Description: { type: "string" },
}
}
},
batch: true,
transport: {
read: function (e) {
return divisionListData;
}
})
})
function ReadList() {
//this.set("isDisabled", false);
var clientContext = new SP.ClientContext.get_current();
// denote that we will be performing operations on the current web
var web = clientContext.get_web();
// denote that we will be querying the "Business Divisions" custom SharePoint list
var divisionsList = web.get_lists().getByTitle("Divisions");
// create a CAML query (blank means just return all items)
var camlQuery = new SP.CamlQuery();
// denote that the operation we want to perform is getItems() on the list
var divisionsListItems = divisionsList.getItems(camlQuery);
var fields = 'Include(ID,DivisionCode, DivisionName, OpenDate, CloseDate, Description)';
clientContext.load(divisionsListItems, fields);
clientContext.executeQueryAsync(function () {
// get the list item enumerator
var listItemEnumerator = divisionsListItems.getEnumerator();
// loop through the items in our custom
// "Divisions" SharePoint list
var listItem;
while (listItemEnumerator.moveNext()) {
var division = new Division();
// get the list item we are on
listItem = listItemEnumerator.get_current();
// get the divisions
division.ID = listItem.get_item("ID");
// var lookup_DivisionCode = listItem.get_item("DivisionCode").get_lookupValue();
//lookup_DivisionCode.get_l
var divisionLookupField = new SP.FieldLookupValue();
divisionLookupField = listItem.get_item("DivisionCode");
//var test = divisionLookupField.$2d_1;
if (divisionLookupField != null)
division.DivisionCode = divisionLookupField.$2d_1;
division.DivisionName = listItem.get_item("DivisionName");
division.Description = listItem.get_item("Description");
division.OpenDate = listItem.get_item("OpenDate");
division.CloseDate = listItem.get_item("CloseDate");
divisionListData.push(division);
kendo.bind($("body"), viewModel);
}
})
}

You are pretty close, instead of returning the array inside the read: function(e), you need to call
e.success(yourArrayOfData);

Related

Kendo UI .. translate datasource data before sending to Grid.

I have some data that looks like:
{
"Data":[
[
{"Key":"Commonality","Value":0},
{"Key":"Item","Value":"ExampleItem"
]
"Total":2,
"AggregateResults":null,
"Errors":null
]
}
The format of the JSON cannot be changed.
I need to somehow translate the data to:
{
"Data":[
[
{ Commonality:0}, Item:"ExampleItem"}
]
"Total":2,
"AggregateResults":null,
"Errors":null
]
}
Does Kendo UI have a callback I can use to process the data and pass it back to the datasource once it's been received?
Literally moments after posting my question I realised that I was 99% there!
I was just missing the Total, AgggregateResults etc from my translate function
function parseFunction(response) {
var result = [];
var data = response.Data;
for (var irow = 0; irow < data.length; irow++) {
var newRecord = {};
for (var icol = 0; icol < data[irow].length; icol++) {
var record = data[irow][icol];
newRecord[record.Key] = record.Value;
}
result.push(newRecord);
}
response.Data = result;
return response;
}
And here is it being used in a data source :)
function CreateDataSource() {
var source = new kendo.data.DataSource({
transport: {
read: {
url: 'GetFixturesReport',
}
},
pageSize: itemsPerPage,
type: 'aspnetmvc-ajax',
serverPaging: true,
serverFiltering: true,
serverSorting: true,
schema: {
data: 'Data',
total: 'Total',
errors: 'Errors',
//model: { id: 'Fixture' },
parse: parseFunction,
}
});
return source;
}
I now have a way to supply C# Dynamic objects to a grid view so that I can have truly dynamic columns. It has taken me a lot of experimentation though!
Hope this helps someone else.
Kiran

How do I reset a collection in Titanium Alloy?

A Backbonejs collection has a function to reset a collection for bulk updates. I would like to use this feature in Titanium Alloy when I sync with JSON data from a server but it appears as if this is not being committed/saved to SQLite - I am using an sql adapter.
config: {
columns: {
// stuff
name: "TEXT"
},
adapter: {
type: "sql",
collection_name: "pony",
db_name: Alloy.CFG.db_name
}
}
I have some jasmine tests which keep failing. FYI I have migration script for development that adds 7 items to the collection so that I have something to work with.
describe("pony model", function () {
var Alloy = require("alloy")
data = {name: "My little pony"},
collection,
item;
beforeEach(function(){
collection = Alloy.createCollection('pony');
item = Alloy.createModel('pony');
});
// PASSES
it('can reset all data', function () {
collection.fetch();
expect(collection.length).toEqual(7);
collection.reset(data)
expect(collection.length).toEqual(1);
})
// FAILS
it('saves reset data', function () {
collection.fetch();
expect(collection.length).toEqual(7);
collection.reset(data)
collection.fetch()
expect(collection.length).toEqual(1);
})
afterEach(function () {
item.destroy();
});
})
The way this bug shows in the UI is that when I save that when I sync data with the server the TableView shows the new records then when I go to another view and come back to the same TableView the synced data is gone and replaced with the default data.
The best approach I found (and I shamefully can't remember where I copied the code from) was to do the reset manually. I posted the code to do this: https://gist.github.com/sukima/8321859
Basically I do my own SQL DELETE then a Backbone reset(), then looped INSERT INTO, finally finishing with a backbone trigger("fetch") event. Doing this via backbone's sync was way to slow. And the normal reset() doesn't run sync anyways.
exports.definition = {
config: {
columns: {
// ...
},
adapter: {
type: "sql",
collection_name: "MyModels"
}
},
extendCollection: function(Collection) {
Collection.prototype.destroyAll = function(opt) {
var db = Ti.Database.open(this.config.adapter.db_name);
db.execute("DELETE FROM " + this.config.adapter.collection_name);
db.close();
this.models = [];
if (!opt || !opt.silent) { this.trigger("reset"); }
return this;
};
Collection.prototype.saveAll = function(opt) {
var util = require("alloy/sync/util");
var dbName = this.config.adapter.db_name;
var table = this.config.adapter.collection_name;
var columns = this.config.columns;
var db = Ti.Database.open(dbName);
db.execute("BEGIN;");
this.forEach(function (model) {
if (!model.id) {
model.id = util.guid();
model.attributes[model.idAttribute ] = model.id;
}
var names = [], values = [], q = [];
for (var k in columns) {
names.push(k);
values.push(model.get(k));
q.push("?");
}
var sqlInsert = "INSERT INTO " + table + " (" + names.join(",") + ") VALUES (" + q.join(",") + ");";
db.execute(sqlInsert, values);
});
db.execute("COMMIT;");
db.close();
if (!opt || !opt.silent) { this.trigger("reset"); }
return this;
};
Collection.prototype.refreshFromData = function refreshFromData(data) {
this.destroyAll({silent:true});
this.reset(data, {silent:true});
this.saveAll({silent: true});
this.trigger("fetch");
};
}
};

Kendo Ui Grid - dataItem.set() method not working properly

I have a grid with 4 columns name, age, collection, profit. But when I try to set a number column it's not reflecting on grid.
schema:
{
model:{
fields:{
name:{type:"string"},
age:{type:"number"},
collection: { type:"number", defaultValue:0.00},
profit: { type:"number", defaultValue:0.00}
}
}
}
This code works perfectly:
var grid = $("#grid").data("kendoGrid");
var data = grid.dataSource.at(0);
data.set("name", "John Doe");
But I want to update numeric column:
var grid = $("#grid").data("kendoGrid");
var data = grid.dataSource.at(0);
var collectionVal = 50000;
data.set("collection", collectionVal);
And it's not updating because the column is of type "number".
UPDATE:
pageable:
{
refresh : true,
pageSizes: true
},
edit: function(e)
{
$('input[name="age"]').blur(function()
{
mygrid = $("#grid").data("kendoGrid");
selectedRow = mygrid.select();
dataItem = mygrid.dataItem(selectedRow);
dataItem.collection = dataItem.age * dataItem.profit;
dataItem.set("collection", dataItem.collection);
});
}
Instead of updating collection in a blur handler defined in the edit, define a save event handler in your grid as follow:
pageable : {
refresh : true,
pageSizes: true
},
save : function (e) {
var profit = e.values.profit || e.model.profit;
var age = e.values.age || e.model.age;
this.dataSource.getByUid(e.model.uid).set("collection", age * profit);
}

keep the Ids of selected results of Kendo UI Autocomplete in a hidden input

I wrote this code to use kendo UI autocomplete. I need to show the title of the selected result in the textbox and keep the if in some hidden input, how can I get the id. it seems the select doesn't work.
$("[data-autocomplete]").each(function () {
var luurl = $(this).attr('data-lookupurl');
var thisElemt = $(this);
$(this).kendoAutoComplete({
minLength: 3,
separator: ", ",
dataTextField: "title",
select: function (e) {
var selectedOne = this.dataItem(e.item.Index());
console.log(kendo.stringify(selectedOne));
},
dataSource: new kendo.data.DataSource({
serverFiltering: true,
serverPaging: true,
pageSize: 20,
transport: {
read: luurl,
dataType: "json",
parameterMap: function (data) {
return { title: thisElemt.val() };
},
schema: {
model: {
id: "id",
fields: {
id: { type: "id" },
title: { type: "string" }
}
}
}
}
})
});
});
There is a typo error, you should use: e.item.index() instead of e.item.Index() (index is lowercase).
So the select function would be:
select : function (e) {
var selectedOne = this.dataItem(e.item.index());
console.log(kendo.stringify(selectedOne));
},
and easier way is :
var autocomplete = $("#autoCompleteId").data("kendoAutoComplete");
console.log(autocomplete.listView._dataItems[0]);
you can access to select data item in autocomplete.listView._dataItems[0] object
you can use script
<script>
$(document).ready(function () {
$("#categories").change(function () {
var url = '#Url.Content("~/")' + "Limitations/ThanaByDistrict_SelectedState";
var ddlsource = "#categories";
var ddltarget = "#target";
$.getJSON(url, { Sel_StateName: $(ddlsource).val() }, function (data) {
$(ddltarget).empty();
$(ddltarget).val(data);
});
});
});
</script>
in controller like
// Get selected combox value
public JsonResult ThanaByDistrict_SelectedState ( Guid Sel_StateName )
{
JsonResult result = new JsonResult ( );
objects temp=db . objects . Single ( m => m . ob_guid == Sel_StateName );
result . Data = temp.ob_code;
result . JsonRequestBehavior = JsonRequestBehavior . AllowGet;
return result;
}
For details you can see this LINK

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);

Resources