KendoUI Grid serverpaging - grid

I'm trying to populate a KendoUI grid with JSON data where the server returns the total number of rows along with the data, but I'm having some trouble getting serverPaging to work properly. I create and assign the dataSource of the grid as follows:
var oDS = new kendo.data.DataSource({
schema: {
data: "data",
total: "total"
},
data: self.grdTableData,
serverPaging: true,
pageSise: 50,
total: joOutput["TotalRecords"]
});
grdTableResults.setDataSource(oDS);
and the first page shows the first 50 of 939 records but there is only ever 1 page (the navigation arrows never respond to anything) and I see NaN - NaN of 939 items and the rotating circle of dots in the centre of the grid that never goes away.
One thing that is different in all the examples I've looked at is that my $.ajax call and the the processing of the JSON data in .done doesn't use "transport: read" but I'm thinking how I send the data and get it back shouldn't matter (or does it because every page request is a new server read?). But I don't think I'm doing enough to handle the server paging properly even though it seems I'm setting data source values similar to those set in the example at http://jsfiddle.net/rusev/Lnkug/. Then there's the "take" and "skip" values that I'm not sure about, but I do have "startIndex" and "rowsPerPage" that I'm sending to the server that can be used there. I assume the grid can tell me what page I'm on show I can set my "startIndex" appropriately and if I have an Items per Page" drop down I can reset my "rowsPerPage" value?
Anyway, sorry for all the newbie questions. Any help and suggestions is genuinely appreciated. Thanks!

transport: read
You should be able to use "transport: read" even if you have custom logic by setting the value to a function. I have created a JS Fiddle to demonstrate this functionality.
dataSource: {
serverPaging: true,
schema: {
data: "data",
total: "total"
},
pageSize: 10,
transport: {
read: function(options) {
var data = getData(options.data.page);
options.success(data);
}
},
update: function() {}
}
Your read function contains a parameter that contains the following paging properties: page, pageSize, skip, take. Keep in mind that all transport operations need to be functions if one operation contains a function.
startIndex and rowsPerPage
If your server accepts these parameters, you should be able to submit them in the read function. Create a new ajax call that post customized data
var ajaxPostData = { startIndex: options.data.skip, rowsPerPage: options.data.pageSize }

This is the code for server side wrapper that I'm using to implement server paging with kendo grid:
#(Html.Kendo().Grid<IJRayka.Core.Utility.ViewModels.ProductDto>()
.Name("productList")
.Columns(columns =>
{
columns.Bound(prod => prod.Name);
columns.Bound(ord => ord.Brand);
columns.Bound(ord => ord.UnitPackageOption);
columns.Bound(ord => ord.CategoryName);
columns.Bound(ord => ord.Description);
})
.Pageable(pager => pager.PageSizes(true))
.Selectable(selectable => selectable.Mode(GridSelectionMode.Multiple))
.PrefixUrlParameters(false)
.DataSource(ds => ds.Ajax()
.Model(m => m.Id(ord => ord.ID))
.PageSize(5)
.Read(read => read
.Action("FilterProductsJson", "ProductManagement")
.Data("getFilters"))
)
)
Where getFilters is a javascript function that passes my custom filter parameters to the grid when it wants to get data from url/service:
function getFilters() {
return {
brand: $("#Brand").val(),
name: $("#Name").val(),
category: $("#CategoryName").val()
};
}
In addition you should implement your controller's action method using kendo's DataSourceRequest class like below, or otherwise it won't work the way you want:
public JsonResult FilterProductsJson([DataSourceRequest()] DataSourceRequest request,
// three additional paramerters for my custom filtering
string brand, string name, string category)
{
int top = request.PageSize;
int skip = (request.Page - 1) * top;
if(brand != null)
brand = brand.Trim();
if(name != null)
name = name.Trim();
if(category != null)
category = category.Trim();
var searchResult = new ManageProductBiz().GetPagedFilteredProducts(brand, name, category, top, skip);
// remove cyclic references:
searchResult.Items.ForEach(prd => prd.Category.Products = null);
return Json(new DataSourceResult { Data = searchResult.Items, Total = searchResult.TotalCount }, JsonRequestBehavior.AllowGet);
}

Related

How do I return an entire paged set from the Jira API using Ramda?

I'm using the Nodejs library for talking to Jira called jira-connector. I can get all of the boards on my jira instance by calling
jira.board.getAllBoards({ type: "scrum"})
.then(boards => { ...not important stuff... }
the return set looks something like the following:
{
maxResults: 50,
startAt: 0,
isLast: false,
values:
[ { id: ... } ]
}
then while isLast === false I keep calling like so:
jira.board.getAllBoards({ type: "scrum", startAt: XXX })
until isLast is true. then I can organize all of my returns from promises and be done with it.
I'm trying to reason out how I can get all of the data on pages with Ramda, I have a feeling it's possible I just can't seem to sort out the how of it.
Any help? Is this possible using Ramda?
Here's my Rx attempt to make this better:
const pagedCalls = new Subject();
pagedCalls.subscribe(value => {
jira.board.getAllBoards({ type:"scrum", startAt: value })
.then(boards => {
console.log('calling: ' + value);
allBoards.push(boards.values);
if (boards.isLast) {
pagedCalls.complete()
} else {
pagedCalls.next(boards.startAt + 50);
}
});
})
pagedCalls.next(0);
Seems pretty terrible. Here's the simplest solution I have so far with a do/while loop:
let returnResult = [];
let result;
let startAt = -50;
do {
result = await jira.board.getAllBoards( { type: "scrum", startAt: startAt += 50 })
returnResult.push(result.values); // there's an array of results under the values prop.
} while (!result.isLast)
Many of the interactions with Jira use this model and I am trying to avoid writing this kind of loop every time I make a call.
I had to do something similar today, calling the Gitlab API repeatedly until I had retrieved the entire folder/file structure of the project. I did it with a recursive call inside a .then, and it seems to work all right. I have not tried to convert the code to handle your case.
Here's what I wrote, if it will help:
const getAll = (project, perPage = 10, page = 1, res = []) =>
fetch(`https://gitlab.com/api/v4/projects/${encodeURIComponent(project)}/repository/tree?recursive=true&per_page=${perPage}&page=${page}`)
.then(resp => resp.json())
.then(xs => xs.length < perPage
? res.concat(xs)
: getAll(project, perPage, page + 1, res.concat(xs))
)
getAll('gitlab-examples/nodejs')
.then(console.log)
.catch(console.warn)
The technique is pretty simple: Our function accepts whatever parameters are necessary to be able to fetch a particular page and an additional one to hold the results, defaulting it to an empty array. We make the asynchronous call to fetch the page, and in the then, we use the result to see if we need to make another call. If we do, we call the function again, passing in the other parameters needed, the incremented page number, and the merge of the current results and the ones just received. If we don't need to make another call, then we just return that merged list.
Here, the repository contains 21 files and folders. Calling for ten at a time, we make three fetches and when the third one is complete, we resolve our returned Promise with that list of 21 items.
This recursive method definitely feels more functional than your versions above. There is no assignment except for the parameter defaulting, and nothing is mutated along the way.
I think it should be relatively easy to adapt this to your needs.
Here is a way to get all the boards using rubico:
import { pipe, fork, switchCase, get } from 'rubico'
const getAllBoards = boards => pipe([
fork({
type: () => 'scrum',
startAt: get('startAt'),
}),
jira.board.getAllBoards,
switchCase([
get('isLast'),
response => boards.concat(response.values),
response => getAllBoards(boards.concat(response.values))({
startAt: response.startAt + response.values.length,
})
]),
])
getAllBoards([])({ startAt: 0 }) // => [...boards]
getAllBoards will recursively get more boards and append to boards until isLast is true, then it will return the aggregated boards.

Why doesn't my datastore send the changes back to the server, if I change only 1 row?

I have a problem, which I cannot solve alone. So your help is very appreciated.
Here we go:
Always if I edit more than one row in my grid, I get a list of beans in my controller for further proceedings...e.g. save the changes, but if I edit only 1 row I get an empty list back or the list is null. It is only working if I edit more than 1 row.
Here is my store and proxy:
var billRecordStore = null;
function createbillRecordStore() {
var billRecordProxy = new Ext.data.HttpProxy({
api : {
read : applicationPath + '/filterRecords',
update : applicationPath + '/updateRecords'
},
type : 'json',
reader : {
type : 'json',
root : 'data',
idProperty : 'brid',
totalProperty : 'total'
},
writer : {
type : 'json'
},
actionMethods: {
create: 'POST', read: 'POST', update: 'POST', destroy: 'POST'
},
simpleSortMode: true
});
billRecordStore = Ext.create('Ext.data.Store', {
pageSize : 25,
model : 'billRecordModel',
storeId : 'billRecordStore',
proxy : billRecordProxy,
remoteSort : false,
autoLoad : false
});
}
That is my SpringMVC controller:
#ResponseBody
#RequestMapping(value = "/updateRecords", method =
{RequestMethod.POST, RequestMethod.GET}, produces =
"application/json")
public ResponseWrapper updateBillrecord(
#RequestBody List<BillRecordsDTO> dirtyBillRecords
) {
if (dirtyBillRecords != null && dirtyBillRecords.size() > 0)
{
billRecordService.updateBillRecords(dirtyBillRecords);
}
return null;
}
This list List<BillRecordsDTO> dirtyBillRecords is allways null if I am editing only 1 row in the grid. More than 1 edited row is working perfectly.
I have no exception thrown at the server side.
In the frontend I get only this exception in the chrome browser:
POST http://localhost:8080/servicetool/updateRecords?_dc=1384181576575 400 (Bad Request) ext-all-debug.js:32379
Ext.define.request ext-all-debug.js:32379
Ext.define.doRequest ext-all-debug.js:71730
Ext.define.update ext-all-debug.js:71455
Ext.define.runOperation ext-all-debug.js:74757
Ext.define.start ext-all-debug.js:74704
Ext.define.batch ext-all-debug.js:42884
Ext.define.sync ext-all-debug.js:43606
Ext.define.save ext-all-debug.js:43634
saveChanges billRecordController.js:113
Ext.create.items.tbar.handler serviceToolView.js:206
Ext.define.fireHandler ext-all-debug.js:46226
Ext.define.onClick ext-all-debug.js:46216
(anonymous function)
wrap
Any ideas? You need more information? Just tell me.
Thank you very much in advance.
edfred
Check out the allowSingle config in the JSON Writer documentation.
By default, the JSON Writer will send single records as an object, while sending multiple records as an array. Setting allowSingle to false tells the writer to always wrap the request data in an array, regardless of the number of records being written.
EDIT: You should be able to see this in action by looking at the POST. In your current configuration, you should see a marked difference between the request sent for one record vs. a request sent for multiple records. Once you switch the allowSingle config to false, however, the requests should look quite a bit the same, except for the size of the array being sent.

rebind properties in model, emberjs

I have just started to use ember.js. I have two models in my application. One that holds data and one that holds this data edited by user. I bind them using one-way binding.
App.ViewModel = Ember.Object.create({
title:'title',
text:'text',
)};
App.EditModel = Ember.Object.create({
titleBinding: Ember.Binding.oneWay('App.ViewModel.title'),
textBinding: Ember.Binding.oneWay('App.ViewModel.text'),
)};
I let a user edit the data in EditModel model. But if the user discard the changes I want to be able to set the values back to the state before editing, ie. to the values in ViewModel.
Is there a way to rebind those properties? Or to manualy rise change event on properties in ViewModel so EditModel gets updated? Or any other approach to my problem?
You could create a custom Mixin which handles the reset for a model, see http://jsfiddle.net/pangratz666/CjB4S/
App.Editable = Ember.Mixin.create({
startEditing: function() {
var propertyNames = this.get('propertyNames');
var props = this.getProperties.apply(this, propertyNames);
this.set('origProps', props);
},
reset: function() {
var props = this.get('origProps');
Ember.setProperties(this, props);
}
});
App.myModel = Ember.Object.create(App.Editable, {
propertyNames: ['title', 'text'],
title: 'le title',
text: 'le text'
});
And later in the views you just invoke the startEditing when you want to take a snapshot of the current values and reset when you want to reset to the previous snapshot of the values.

How do i bind the json data to a asp.net dropdownlist using jquery?

I am trying to design a cascading dropdown. i am using 3 asp.net dropdowns. THe first one on page load loads the countries. Then when a country is selected i do a ajax call to a webmethod. I fetch the data for the teams belonging to that country. The data is in a dataset which i convert into JSON and then return it. On success what code do i need to add to bind the json data to the dropdown list.
below is the code.
$(document).ready(function() {
$('#ddlcountries').change(function() {
debugger;
var countryID = $('#ddlcountries').val();
$.ajax({
type: "POST",
url: "Default.aspx/FillTeamsWM",
data: '{"CountryID":' + countryID + '}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(jsonObj) {
/* WHAT CODE DO I ADD HERE TO BIND THE JSON DATA
TO ASP.NET DROP DOWN LIST. I DID SOME GOOGLING
BUT COULD NOT GET PROPER ANSWER */
},
error: function() {
alert('error');
}
});
});
});
Depending on what you're passing back to the client, I am going to assume it's a List<string>. You can adjust the code accordingly depending on what you're passing back to the client, since you're not telling us what is being passed back.
So if that is the case do something like this:
// first remove the current options if any
$('#ddlTeams').find('option').remove();
// next iterate thru your object adding each option to the drop down\
$(jsonObj).each(function(index, item){
$('#ddlTeams').append($('<option></option>').val(item).html(item));
});
Assuming again, if your List has an object containing teamid and `teamname11
// first remove the current options if any
$('#ddlTeams').find('option').remove();
// next iterate thru your object adding each option to the drop down\
$(jsonObj).each(function(index, item){
$('#ddlTeams').append($('<option></option>').val(item.teamid).html(item.teamname));
});
It is dependent on the data you are getting back from the server but this is what I came up with presuming it was a simple json structure, I was also wondering whether it may be better to send the data on the first request, and forget about the ajax.
$('#continent').change(function() {
// success function
$('#country').children().remove();
for (var country in json.continents[$(this).val()]) {
var $elm = $('<option>').attr('value', country)
.html(country);
$('#country').append($elm);
}
})
Here is a demo;
Edit: Given your data structure have update so something like this
var teams = json['TeamList'];
$('#teamid').change(function() {
// success function
var $t = $(this);
var $select = $('#teamname');
var i = (function() {
for (var i=0; i<teams.length; i++) {
if (teams[i]['teamid'] == $t.val()) {
return i;
}
}
})()
var name = teams[i]['teamname'];
var $elm = $('<option>').val(name).html(name);
$select.children().remove();
$select.append($elm);
})
see here for demo, please note this may requiring some changing to fit your specific use case, but it demonstrates simple iteration over arrays and objects

In MVC app using JQGrid - how to set user data in the controller action

How do you set the userdata in the controller action. The way I'm doing it is breaking my grid. I'm trying a simple test with no luck. Here's my code which does not work. Thanks.
var dataJson = new
{
total =
page = 1,
records = 10000,
userdata = "{test1:thefield}",
rows = (from e in equipment
select new
{
id = e.equip_id,
cell = new string[] {
e.type_desc,
e.make_descr,
e.model_descr,
e.equip_year,
e.work_loc,
e.insp_due_dt,
e.registered_by,
e.managed_by
}
}).ToArray()
};
return Json(dataJson);
I don't think you have to convert it to an Array. I've used jqGrid and i just let the Json function serialize the object. I'm not certain that would cause a problem, but it's unnecessary at the very least.
Also, your user data would evaluate to a string (because you are sending it as a string). Try sending it as an anonymous object. ie:
userdata = new { test1 = "thefield" },
You need a value for total and a comma between that and page. (I'm guessing that's a typo. I don't think that would compile as is.)
EDIT:
Also, i would recommend adding the option "jsonReader: { repeatitems: false }" to your javascript. This will allow you to send your collection in the "rows" field without converting it to the "{id: ID, cell: [ data_row_as_array ] }" syntax. You can set the property "key = true" in your colModel to indicate which field is the ID. It makes it a lot simpler to pass data to the grid.

Resources