knockout dynamic binding issue - binding

Consider the following ViewModel that is generated through the knockout mapping plugin.
var originalData = {
"QuoteSelectedViewModel": {
"ProductName": "Select",
"CoverQuotesViewModel": [
{
"Code": 1,
"Label": "Première Assistance 24h/24 (GRATUITE)",
"IsMandatory": true,
"IsSelected": true,
"DependsOn": []
},
{
"Code": 2,
"Label": "Assistance PLUS 24h/24",
"IsMandatory": false,
"IsSelected": false,
"DependsOn": []
},
{
"Code": 8,
"Label": "Heurts Animaux / Force de la Nature",
"IsMandatory": false,
"IsSelected": false,
"DependsOn": [
2
]
},
]}
}
var viewModel = ko.mapping.fromJS(originalData);
ko.applyBindings(viewModel);
<div data-bind="with: QuoteSelectedViewModel">
selected quote is : <span data-bind="text: ProductName"></span>
<!-- ko foreach: CoverQuotesViewModel -->
<br/>
<div data-bind: if: IsVisible>
<input type="checkbox" data-bind="checked: IsSelected"></input>
<input type="text" data-bind="value: Label, enable: IsSelected"></input>
</div>
<!-- /ko -->
</div>
Now, I would like to hide the div when IsVisible returns false. IsVisible does not exist yet, and it should be a computed observable function on each element of the CoverQuotesViewModel array.
How do I generate this computed observable function on each element ?
Thanks
[EDIT]
I've added a jsfiddle here : http://jsfiddle.net/graphicsxp/fpKWM/
[EDIT2]
Actually knockout document is clear about how to do that:
Of course, inside the create callback you can do another call to
ko.mapping.fromJS if you wish. A typical use-case might be if you want
to augment the original JavaScript object with some additional
computed observables:
var myChildModel = function(data) {
ko.mapping.fromJS(data, {}, this);
this.nameLength = ko.computed(function() {
return this.name().length;
}, this); }
[EDIT]
Here's the full code following Paul's suggestion:
(getQuotesSuccess is an AJAX success handler)
viewModel.getQuotesSuccess = function (result) {
var myCoverQuotesViewModel = function (data, parent) {
var self = this;
ko.mapping.fromJS(data, {}, this);
self.IsVisible = ko.computed(function () {
var visible = true;
if (self.DependsOn().length > 0) {
$.each(self.DependsOn(), function (index, value) {
var dependency = viewModel.QuoteSelectedViewModel().CoverQuotesViewModel.filterByProperty("Code", value);
if (dependency().length > 0) {
visible = visible & dependency()[0].IsSelected();
} else {
visible = false;
}
});
}
return visible;
}, this);
}
var mapping = {
'CoverQuotesViewModel': {
create: function (options) {
return new myCoverQuotesViewModel(options.data, options.parent);
}
}
}
ko.mapping.fromJS(result, mapping, viewModel);
};

Ok, reverting back to my earlier answer, with your modifications, so anyone else looking at this answer actually gets the correct version!
You need to create a child viwe model, and use the mapping plugin to populate it automatically, then add in your computed observable:
function CoverQuotesViewModel(data)
{
var self = this;
ko.mapping.fromJS(data, {}, self);
// Copy the data to each property.
self.IsVisible = ko.computed(function()
{
// your logic for each quote
});
}
Then you need to use a create map for the mapping of the main view model, and in this you create your child view model:
var mapping = {
'CoverQuotesViewModel': {
create: function(options) {
var model = new CoverQuotesViewModel(options.data);
return model;
}
}
}
var viewModel = ko.mapping.fromJS(data, mapping);
You don't need to pass this into the computed, as you are referencing self, which is your stored version of this.

Related

Select2 doesn't work change value from jQuery (dataAdapter)

I have a huge json data source (over 50,000 + lines) loaded in memory from a static file.
Note: It's not important why I have it in a static file.
I use select2 (v 4.0.5) that initializes as:
function initSelect2(selectName, dataSelect) {
var pageSize = 20;
$.fn.select2.amd.require(["select2/data/array", "select2/utils"],
function (ArrayData, Utils) {
function CustomData($element, options) {
CustomData.__super__.constructor.call(this, $element, options);
}
Utils.Extend(CustomData, ArrayData);
CustomData.prototype.query = function (params, callback) {
if (!("page" in params)) {
params.page = 1;
}
var data = {};
data.results = dataSelect.slice((params.page - 1) * pageSize, params.page * pageSize);
data.pagination = {};
data.pagination.more = params.page * pageSize < dataSelect.length;
callback(data);
};
$('#mySelect3').select2({
ajax: {},
dataAdapter: CustomData,
width: '100%'
});
});
}
I have one big problem. I can not set the value to select from jQuery. If I try like this:
$ ("#mySelect3").val(17003).trigger("change");
nothing will happen. But I think I'm doing it badly. If I understand the documentation I think I should implement function:
CustomData.prototype.current = function (callback) {}
that should create the data, and then function:
CustomData.prototype.query = function (params, callback) {}
should only filter them.
Can you please help me, how do I implement select2 initialization, that can work with many options and can by set from jQuery?
With custom data adapter you don't need pagination :
// create huge array
function mockData() {
var hugeArray = [];
for (let i = 0; i < 50000; i++) {
el = {
id: i,
text: 'My mock data ' + i,
};
hugeArray.push(el);
}
return hugeArray;
};
// define custom dataAdapter
$.fn.select2.amd.define("myCustomDataAdapter",
['select2/data/array','select2/utils'],
function (ArrayData, Utils) {
function CustomData ($element, options) {
CustomData.__super__.constructor.call(this, $element, options);
};
Utils.Extend(CustomData, ArrayData);
CustomData.prototype.query = function (params, callback) {
var data = {
// here replace mockData() by your array
results: mockData()
};
callback(data);
};
return CustomData;
}
);
//
$('#mySelect3').select2({
allowClear: true,
// use dataAdapter here
dataAdapter:$.fn.select2.amd.require("myCustomDataAdapter"),
});
And with search you can do like this :
// create huge array
function mockData() {
var hugeArray = [];
for (let i = 0; i < 50000; i++) {
el = {
id: i,
text: 'My mock data ' + i,
};
hugeArray.push(el);
}
return hugeArray;
};
// define custom dataAdapter
$.fn.select2.amd.define("myCustomDataAdapter",
['select2/data/array','select2/utils'],
function (ArrayData, Utils) {
function CustomData ($element, options) {
CustomData.__super__.constructor.call(this, $element, options);
};
Utils.Extend(CustomData, ArrayData);
CustomData.prototype.query = function (params, callback) {
var data = {
// here replace mockData() by your array
results: mockData()
};
if ($.trim(params.term) === '') {
callback(data);
} else {
if (typeof data.results === 'undefined') {
return null;
}
var filteredResults = [];
data.results.forEach(function (el) {
if (el.text.toUpperCase().indexOf(params.term.toUpperCase()) == 0) {
filteredResults.push(el);
}
});
if (filteredResults.length) {
var modifiedData = $.extend({}, data, true);
modifiedData.results = filteredResults;
callback(modifiedData);
}
return null;
}
};
return CustomData;
}
);
//
$('#mySelect3').select2({
minimumInputLength: 2,
tags: false,
allowClear: true,
// use dataAdapter here
dataAdapter:$.fn.select2.amd.require("myCustomDataAdapter"),
});
I had the same issue and this is how I solved it.
Note: We are using dataAdapter because we dealing with large that, so I am assuming your drop-down will contain large amount of data.
After implementing your DataAdapter with a query use this example to initialize your select2.
if(selectedValue !== null )
{
$("#item_value").select2({
placeholder: 'Select an option',
allowClear: true,
disabled: false,
formatLoadMore: 'Loading more...',
ajax: {},
data: [{ id: selectedValue, text: selectedValue }],
dataAdapter: customData
});
$("#item_value").val(selectedValue).trigger('change');
}else{
$("#item_value").select2({
placeholder: 'Select an option',
allowClear: true,
disabled: false,
formatLoadMore: 'Loading more...',
ajax: {},
dataAdapter: customData
});
}
To set selected value in select2 you need to pass some data into data option, but as we are dealing with large amount of data. You can't pass the complete array of large data you have as it's going to cause your browser window to freeze and lead to a bad user performance.
But instead set the data option only with the selected value you got from db or variable.
I hope this helps.

How to bind a list to a navigation property

I have a master/detail application for directories and files. In my OData service i have a navigation property that leads from a directory to a set of files. I have a list in the detail view for the files of the directory. But i am having trouble binding it to the navigation property of the OData service
<mvc:View xmlns:core="sap.ui.core" xmlns:f="sap.ui.layout.form" xmlns:l="sap.ui.layout" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" controllerName="FileUtility.view.Detail">
<Page id="detailPage" navButtonPress="onNavBack" showNavButton="{device>/isPhone}" title="Files">
<content>
<ObjectHeader iconActive="false" id="detailHeader" introActive="false" number="" numberUnit="" title="" titleActive="false">
<attributes id="detailAttributes">
<ObjectAttribute active="false" id="attribute" text="{i18n>detailText}"/>
</attributes>
<firstStatus id="detailStatus">
<ObjectStatus id="status" text=""/>
</firstStatus>
</ObjectHeader>
<List id="__list0" noDataText="Drop list items here" items="{path :'DirectorySet>/FileSet'}">
<items>
<ObjectListItem counter="0" id="__item5" showMarkers="false" title="{Name}" type="Active">
</ObjectListItem>
</items>
<core:ExtensionPoint name="extDetail"/>
</List>
</content>
<footer id="detailFooter">
<Toolbar id="detailToolbar">
<content>
<ToolbarSpacer id="toolbarSpacer"/>
<Button icon="sap-icon://action" id="actionButton" press="openActionSheet"/>
</content>
</Toolbar>
</footer>
</Page>
</mvc:View>
The items path is the source entity set name. Not sure where im supposed to get this name. The FileSet portion is from the navigation property. I am confused as how to map it in the view.
EDIT: i have removed the "item = { }" from the List tag and tried to bind it in the Detail.js file.
sap.ui.core.mvc.Controller.extend("FileUtility.view.Detail", {
onInit : function() {
this.oInitialLoadFinishedDeferred = jQuery.Deferred();
if(sap.ui.Device.system.phone) {
//Do not wait for the master when in mobile phone resolution
this.oInitialLoadFinishedDeferred.resolve();
} else {
this.getView().setBusy(true);
var oEventBus = this.getEventBus();
oEventBus.subscribe("Component", "MetadataFailed", this.onMetadataFailed, this);
oEventBus.subscribe("Master", "InitialLoadFinished", this.onMasterLoaded, this);
}
this.getRouter().attachRouteMatched(this.onRouteMatched, this);
},
onMasterLoaded : function (sChannel, sEvent) {
this.getView().setBusy(false);
this.oInitialLoadFinishedDeferred.resolve();
},
onMetadataFailed : function(){
this.getView().setBusy(false);
this.oInitialLoadFinishedDeferred.resolve();
this.showEmptyView();
},
onRouteMatched : function(oEvent) {
var oParameters = oEvent.getParameters();
var oView = this.getView();
var sEntityPath = "/" + oParameters.arguments.entity;
var oContext = new sap.ui.model.Binding(this.getView().getModel(), sEntityPath + '/FileSet');
this.getView().setBindingContext(oContext);
//var oList = oView.byId("__list0");
//oList.bindItems(sEntityPath + '/FileSet',sap.ui.getCore().byId(this.getView().byId('__item5').getId()));
//sap.ui.getCore().byId(this.getView().byId('__list0').getId()).bindItems(sEntityPath + '/FileSet',sap.ui.getCore().byId(this.getView().byId('__item5').getId()));
//this.bindView(sEntityPath);
jQuery.when(this.oInitialLoadFinishedDeferred).then(jQuery.proxy(function () {
// When navigating in the Detail page, update the binding context
if (oParameters.name !== "detail") {
return;
}
var oIconTabBar = oView.byId("idIconTabBar");
oIconTabBar.getItems().forEach(function(oItem) {
if(oItem.getKey() !== "selfInfo"){
oItem.bindElement(oItem.getKey());
}
});
//var oList = oView.byId("__list0");
//oList.bindItems(sEntityPath + '/FileSet');
//sap.ui.getCore().byId(this.getView().byId('__list0').getId()).bindItems(sEntityPath + '/FileSet',sap.ui.getCore().byId(this.getView().byId('__item0').getId()));
// Specify the tab being focused
var sTabKey = oParameters.arguments.tab;
this.getEventBus().publish("Detail", "TabChanged", { sTabKey : sTabKey });
if (oIconTabBar.getSelectedKey() !== sTabKey) {
oIconTabBar.setSelectedKey(sTabKey);
}
}, this));
},
bindView : function (sEntityPath) {
var oView = this.getView();
oView.bindElement(sEntityPath);
//Check if the data is already on the client
if(!oView.getModel().getData(sEntityPath)) {
// Check that the entity specified was found.
oView.getElementBinding().attachEventOnce("dataReceived", jQuery.proxy(function() {
var oData = oView.getModel().getData(sEntityPath);
if (!oData) {
this.showEmptyView();
this.fireDetailNotFound();
} else {
this.fireDetailChanged(sEntityPath);
}
}, this));
} else {
this.fireDetailChanged(sEntityPath);
}
},
showEmptyView : function () {
this.getRouter().myNavToWithoutHash({
currentView : this.getView(),
targetViewName : "FileUtility.view.NotFound",
targetViewType : "XML"
});
},
fireDetailChanged : function (sEntityPath) {
this.getEventBus().publish("Detail", "Changed", { sEntityPath : sEntityPath });
},
fireDetailNotFound : function () {
this.getEventBus().publish("Detail", "NotFound");
},
onNavBack : function() {
// This is only relevant when running on phone devices
this.getRouter().myNavBack("main");
},
onDetailSelect : function(oEvent) {
sap.ui.core.UIComponent.getRouterFor(this).navTo("detail",{
entity : oEvent.getSource().getBindingContext().getPath().slice(1),
tab: oEvent.getParameter("selectedKey")
}, true);
},
openActionSheet: function() {
if (!this._oActionSheet) {
this._oActionSheet = new sap.m.ActionSheet({
buttons: new sap.ushell.ui.footerbar.AddBookmarkButton()
});
this._oActionSheet.setShowCancelButton(true);
this._oActionSheet.setPlacement(sap.m.PlacementType.Top);
}
this._oActionSheet.openBy(this.getView().byId("actionButton"));
},
getEventBus : function () {
return sap.ui.getCore().getEventBus();
},
getRouter : function () {
return sap.ui.core.UIComponent.getRouterFor(this);
},
onExit : function(oEvent){
var oEventBus = this.getEventBus();
oEventBus.unsubscribe("Master", "InitialLoadFinished", this.onMasterLoaded, this);
oEventBus.unsubscribe("Component", "MetadataFailed", this.onMetadataFailed, this);
if (this._oActionSheet) {
this._oActionSheet.destroy();
this._oActionSheet = null;
}
}
});
I have added the binding code to the "onRouteMatched" method.
EDIT 2:
My binding in the controller:
var oList = oView.byId("__list0");
var oTemplate = this.getView().byId('__item5');
oList.bindItems(sEntityPath + '/FileSet',sap.ui.getCore().byId(oTemplate.getId()));
I am not getting any data back but the path in the SAPUI5 debugger is correct despite being marked as "invalid"
EDIT 3
I got it working using this code in the onRouteMatched function
var oList = oView.byId("__list0");
var oTemplate = oView.byId('__item5');
oTemplate.bindProperty('title', 'Name');
oList.bindItems(sEntityPath + '/FileSet', sap.ui.getCore().byId(oTemplate.getId()));
I think what you are missing is just setting the binding context on the detail view(Maybe you have have not seen the controller code).
Lets say you have 2 entities Folders and Files. Your Folders has a navigation property FileSet to Files.
Now you have Folders entity bound to the Master entity. But when you click on the Master and detail should load the files of A Folder so then you will have bind the detail view to the selected entry in master.
How can you get the selected entry in Master view??
In the event handler on action on Master you can call
this.getBindingContext().getPath()
and pass this over to the detail view. In the detail you can call
var oContext = new sap.ui.model.Binding(oModel,sPath)
//sPath is the path from master view , oModel is the oData model of your application
this.getView().setModel(oModel);
this.getView().setBindingContext(oContext);
//Now the FileSet of your list will fire and load the data in your list.
Hope this helps.
You are binding to a named model but are not referencing the "named" model in your code.
i.e. in your code you have
="{path :'DirectorySet>/FileSet'}">
yet in your controller none of your code references this model
e.g.
this.getView().getModel()
you should specify the name of the model (as you can have several models AND you appear to be binding to a named model.
If you initially named the model in question DirectorySet then specify that in the relevant operations - e.g.:
this.getView().getModel("DirectorySet")
I haven't been through all the code but this would be a good start.
EDIT:
Use the following to get the ACTUAL values:
jQuery.sap.log.setLevel(jQuery.sap.log.LogLevel['INFO']);
jQuery.sap.log.info("fully qualified path: " + sEntityPath + '/FileSet',sap.ui.getCore().byId(oTemplate.getId()));
Just want to be sure we are getting the full and correct binding path.

Tweaking contextmenu in jstree

I would like to do the following with the contextmenu plugin:
- Rename "Create" as "Add"
- Remove "Edit"
How does one do it?
I do NOT want to create a custom menu because then I only get a node and not the nice data object that can be used in the Create, Rename and Delete events.
Found the answer in the code of jstree itself:
Added this to the jstree code:
"contextmenu": {
items: customContextMenu
}
And this for the context menu items:
function customContextMenu() {
'use strict';
var items = {
"create" : {
"separator_before": false,
"separator_after": true,
"_disabled": false, //(this.check("create_node", data.reference, {}, "last")),
"label": "Add",
"action": function (data) {
var inst = $.jstree.reference(data.reference),
obj = inst.get_node(data.reference);
inst.create_node(obj, {}, "last", function (new_node) {
setTimeout(function () { inst.edit(new_node); }, 0);
});
}
},
"rename" : {
"separator_before": false,
"separator_after": false,
"_disabled": false, //(this.check("rename_node", data.reference, this.get_parent(data.reference), "")),
"label": "Rename",
"action": function (data) {
var inst = $.jstree.reference(data.reference),
obj = inst.get_node(data.reference);
inst.edit(obj);
}
},
"remove" : {
"separator_before": false,
"icon": false,
"separator_after": false,
"_disabled": false, //(this.check("delete_node", data.reference, this.get_parent(data.reference), "")),
"label": "Withdraw",
"action": function (data) {
var inst = $.jstree.reference(data.reference),
obj = inst.get_node(data.reference);
if (inst.is_selected(obj)) {
inst.delete_node(inst.get_selected());
} else {
inst.delete_node(obj);
}
}
}
};
return items;
}

How to initialize the selection for rails-select2 in BackboneForms schema?

The project uses marionette-rails, backbone-on-rails, select2-rails and this port to BackboneForms to provide a multiselect form field. The select options are available to the user. They are retrieved from the collection containing the total list of options:
MyApp.module("Products", function(Products, App, Backbone, Marionette, $, _) {
Products.CustomFormView = Products.CustomView.extend({
initialize: function(options) {
this.model.set("type", "Product");
Products.EntryView.prototype.initialize.apply(this, arguments);
},
schemata: function() {
var products = this.collection.byType("Product");
var productTypes = products.map(function(product){
return {
val: product.id,
label: product.get("name")
};
});
return {
productBasics: {
name: {
type: "Text",
title: "Name",
editorAttrs: {
maxLength: 60,
}
},
type: {
type: 'Select2',
title: "Product type",
options: {
values: productTypes,
value: [3, 5],
initSelection: function (element, callback) {
var data = [];
$(element.val().split(",")).each(function () {
data.push({id: this, text: this});
});
callback(data);
}
},
editorAttrs: {
'multiple': 'multiple'
}
}
}
};
}
});
});
Do I initialize the value correctly in options.value? How comes initSelection is never called? I copied the function from the documentation - it might be incomplete for my case. None of the products with the IDs 3 and 5 is displayed as the selection.
initSelection is only used when data is loaded asynchronously. My understanding is that there is no way of specifying the selection upon initialization if you are using an array as the data source for a Select2 control.
The best way of initializing the selection is by using setValue after the form is created. Here is a simplified example based on the code in your example.
var ProductForm = Backbone.Form.extend({
schema: {
type: {
type: 'Select2',
title: "Product type",
options: {
values: productTypes,
},
editorAttrs: {
'multiple': 'multiple'
}
}
});
var form = new ProductForm({
model: new Product()
}).render();
form.setValue("type", [3, 5]);
You can use value function (http://ivaynberg.github.io/select2/#documentation) in setValue. I personally recomend you to use this backbonme-forms plugin: https://gist.github.com/powmedia/5161061
There is a thread about custom editors: https://github.com/powmedia/backbone-forms/issues/144

Kendo UI Grid not showing JSON data

I am facing this problem for quite a while now with the problem that I am unable to bind JSON data that my controller action is passing to the kendo UI Grid, there were few JavaScript issues before but now they are gone but still my grid is not showing any results:
In Model:
public object GetResult(string id)
{
var sqlCom = new SqlCommand("SELECT [No],[Desc],[Date],[Height],[Final] FROM [cr_form] WHERE [uId]=#id;", sqlConn);
sqlCom.Parameters.AddWithValue("#id", id);
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
JsonWriter jsonWriter = new JsonTextWriter(sw);
var rcrds = GETSQLRESULTS(sqlCom);
try
{
int i = 0;
if (rcrds != null || rcrds.HasRows)
{
//jsonWriter.WriteStartObject();
while (rcrds.Read())
{
jsonWriter.WriteStartObject(); //Changed
for (int j = 0; j < rcrds.FieldCount; j++)
{
jsonWriter.WritePropertyName(rcrds.GetName(j)); // column name
jsonWriter.WriteValue(rcrds.GetValue(j)); // value in column
}
i++;
jsonWriter.WriteEndObject(); //Changed
}
//jsonWriter.WriteEndObject();
}
}
catch (Exception ex) { }
return jsonWriter;
}
In Controller:
public ActionResult GetRecords()
{
var usrObj = new User();
var jsnRslt = usrObj.GetResult(Session["Id"].ToString());
//Till here jsnRslt contains this string: “{"No":null,"Desc":"asfasfasfasfasfasfasfasfasfasfasfasf","Date":"2013-03-27T00:00:00","Height":0,"Final":null,"No":null,"Desc":"etwetwetwetwet","Date":"2013-03-27T00:00:00","Height":0,"Final":0,"No":null,"Desc":"asfasfasfskfjklajsfkjasklfjklasjfklajsfkljaklsfjklasjfkljasfkljlasf","Date":"2013-03-27T00:00:00","Height":0,"Final":0,"No":null,"Desc":"askjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfklaskjfkajsfkl","Date":"2013-03-27T00:00:00","Height":0,"Final":0,"No":null,"Desc":"safasfasfasfasfasf","Date":"2013-03-27T00:00:00","Height":0,"Final":0,"No":null,"Desc":"asfasf","Date":"2013-03-27T00:00:00","Height":0,"Final":0,"No":null,"Desc":"asfasfasf","Date":"2013-03-27T00:00:00","Height":2,"Final":0}”
//After Changes in the Model I am getting it in the required Array format:
//{"No":null,"Desc":"asfasfasfasfasfasfasfasfasfasfasfasf","Date":"2013-03-27T00:00:00","Height":0,"Final":null}
//{"No":null,"Desc":"etwetwetwetwet","Date":"2013-03-27T00:00:00","Height":0,"Final":0}
//{"No":null,"Des...
return Json(jsnRslt, JsonRequestBehavior.AllowGet);
}
In View:
<div>
<script type="text/javascript">
$(document).ready(function () {
$("#grid").kendoGrid({
dataSource: {
type: "json",
serverPaging: true,
pageSize: 5,
groupable: true,
selectable: "row",
transport: { read: { url: "Records", dataType: "json"} }
},
height: 400,
scrollable: true,
sortable: true,
filterable: true,
pageable: true,
columns: [
{ field: "No", title: " No" },
{ field: "Desc", title: "Description" },
{ field: "Date", title: "Date" },
{ field: "Height", title: "Height" },
{ field: "Final", title: "Final" }
],
dataBound: function () {
this.expandRow(this.tbody.find("tr.k-master-row").first());
}
});
});
</script>
</div>
But after all this all I can see is an empty grid. And no errors in JavaScript console.
Please help
The JSON that you return from the server should be array. You currently it seems that you are returning single objects with multiple fields that are the same.
Here is an example how the JSON should look like:
[{"No":null,"Desc":"asfasfasfasfasfasfasfasfasfasfasfasf","Date":"2013-03-27T00:00:00","Height":0,"Final":null},
{"No":null,"Desc":"etwetwetwetwet","Date":"2013-03-27T00:00:00","Height":0,"Final":0},
{"No":null,"Desc":"asfasfasfskfjklajsfkjasklfjklasjfklajsfkljaklsfjklasjfkljasfkljlasf","Date":"2013-03-27T00:00:00","Height":0,"Final":0}]
I think following code will be useful for you and let me know if you have any problem:
$('#gridName').kendoGrid({
dataSource: {
type: "odata",
transport: {
read: {
contentType: "application/json; charset=utf-8",
type: "POST",
url: 'YourURL'
}
},
pageSize: 10,
type: "json"
},
scrollable: true,
sortable: true,
resizable: true
});
Inside you dataSource set data.
data: #Html.Raw(Json.Encode(Model.RemoteObject)),
RemoteObject is you object containing all data.
First I check your tranport read URL. have you trace the controller if it fires the GetRecords command?
transport:
{
read: {
//if you don't use area then remove it
url: "#Url.Action("GetRecords", new { area = "YourAreaName", controller = "YourControllerName" })",
dataType: "json"
}
}
if it still doesn't fix your problem, then modify your Controller,
public ActionResult GetRecords([DataSourceRequest] DataSourceRequest request)
{
var usrObj = new User();
var jsnRslt = usrObj.GetResult(Session["Id"].ToString());
return Json(jsnRslt.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
here's the link to understand the Kendo's ToDataSourceResult

Resources