How do I make search input in kendo grid? - javascript

I am a new Software Developer. In my new company, I use their framework to code. And its using Kendo. I tried to make a search field for Kendo Grid so I can find a specific information in that grid. I tried this method but it doesn't work. Honestly, I don't understand how to use 'transport' things. I call an API to get datas for my grid and I call it in my grid's line of code.
{
type: 'panel',
fields: [{
type: 'panel',
text: 'Payment List',
name: 'payment',
fields: [{
type: 'grid',
name: 'paymentGrid',
data: [],
toolbar: function () {
return `<div class="toolbar" style="width:370px">
<label class="search-label" for="search-reservation" style="color:white"> Cari berdasarkan No. Pesanan: </label>
<input type="search" id="search-reservation" class="search-class">
</div>`
},
sourceOptions: {
pageSize: 10
},
options: {
selectable: true,
autoheight: true,
allowCopy: true,
altrows: true,
pageable: {
refresh: true,
buttonCount: 5,
pageSizes: [10, 20, 50, 100]
},
dataBinding: function () {
record = (this.dataSource.page() - 1) * this.dataSource.pageSize();
}
},
url: function (option) {
var arg = option.data
$.ajax({
method: 'POST',
url: APILink,
data: JSON.stringify(arg),
dataType: 'json',
contentType: 'application/json',
}).done(function (resp) {
if (resp.data != null) {
var nameMap = [];
$.each(resp.data, function (key, val) {
nameMap.push({
id: val.id,
supplier: val.supplier,
reservation_id: val.reservation_id,
currentPayment: val.state
});
});
option.success({
data: nameArray,
total: resp.total
});
}
}).fail(function (jqXHR, status, err) {
option.error(err);
});
},
fields: [{
name: 'number',
text: 'No. ',
template: "#= ++record #",
width: 70,
}, {
name: 'supplier',
text: 'Supplier',
}, {
name: 'reservation_id',
text: 'No. Reservation',
}, {
name: 'currentPayment',
text: 'status',
}, {
name: 'checked',
text: 'choose',
width: 100,
template: function (item) {
return !!item.checked
? `<input id="${item.id}" name='ceklis-boks[]' class="check" checked value="${item.id}" type=\'checkbox\' />`
: `<input id="${item.id}" name='ceklis-boks[]' class="check" value="${item.id}" type=\'checkbox\' />`
}
}],
onDataBound: 'dataBound',
}]
}
Then I used the same code as I mention before in previous link, and replace the ID (#) in that code with mine. But, it won't work. I come to his fiddle and I thought it was because his PlainDs variable and $("#category").kendoAutoComplete({...}) or serverPaging, serverSorting, or serverFiltering. So, I comment all of it here and still working properly. So basically, I can just write the code from line 49 - 81 like in his post. But why it doesn't work? For your information, I call the grid with its name or sometimes I give it a class. But it won't work. Is it a problem if I use class or name instead of ID?

The term "Not working" is too broad here, if you can be more specific on what is not working, we may be able to pinpoint better. However I assume you know how to get the grid to display and so on. so basically to get the search to work I usually have this in the click event of my "Search" button:
var grid = $("#myGrid").data("kendoGrid");
var ds = grid.dataSource;
var searchVal = $("#search-reservation").val();
if ( searchVal ) {
ds.filter({
field: "reservation_id", operator: "eq", value: searchVal
});
}
else {
ds.filter({});
}

Related

How to set cutom template for kendo grid columns

I need to set Kendo grid action button Icon based on value. My code as follows,
function InitProductServicesGrid() {
var prodServiceDataSource = new kendo.data.DataSource({
transport: {
type: "json",
read:
{
url: SERVER_PATH + "/LTSService/ProductsService.asmx/GetProductServiceDetailsList",
type: "POST",
contentType: 'application/json',
data: GetAdditonalData,
datatype: "json"
},
update:
{
url: SERVER_PATH + "/LTSService/ProductsService.asmx/SaveProductService",
type: "POST",
contentType: 'application/json',
datatype: "json"
}
},
schema: {
data: function (result) {
return JSON.parse(result.d);
},
model: {
id: "Id",
fields: {
Id: { type: "int" },
ServiceTime: { type: "string" },
IsActive: { type: "boolean"}
}
}
},
requestEnd: function (e) {
if (e.type === "destroy") {
var grid = $("#productServicesGrid").data("kendoGrid");
grid.dataSource.read();
}
},
error: function (e) {
e.preventDefault();
if (e.xhr !== undefined && e.xhr !== null) {
var messageBody = e.xhr.responseJSON.Message;
ShowGritterMessage("Errors", messageBody, false, '../App_Themes/Default/LtsImages/errorMessageIcon_large.png');
var grid = $("#productServicesGrid").data("kendoGrid");
grid.cancelChanges();
}
},
pageSize: 20,
});
$("#productServicesGrid").kendoGrid({
dataSource: prodServiceDataSource,
sortable: true,
filterable: false,
pageable: true,
dataBound: gridDataBound,
editable: {
mode: "inline",
confirmation: false
},
columns: [
{ field: "Id", title: "", hidden: true },
{
field: "ServiceTime",
title: "Time Standard",
sortable: false,
editor: function (container, options) {
var serviceTimeTxtBox = RenderServiceTime();
$(serviceTimeTxtBox).appendTo(container);
},
headerTemplate: '<a class="k-link" href="#" title="Time Standard">Time Standard</a>'
},
{
title: "Action", command: [
{
name: "hideRow",
click: hideRow,
template: comandTemplate
}
],
width: "150px"
}
]
});
}
I wrote a custom template function as follows,
function comandTemplate(model) {
if (model.IsActive == true) {
return '<a title="Hide" class="k-grid-hideRow k-button"><span class="k-icon k-i-lock"></span></a><a title="Hide"></a>';
}
else {
return '<a title="Show" class="k-grid-hideRow k-button"><span class="k-icon k-i-unlock"></span></a><a title="Show"></a>';
}
}
But when I debug the I saw the following value for model value.
I followed this sample code as well. here you can see, I also set the custom template like the sample code. Please help me to solve this. Why I can't access model IsActive value from comandTemplate function.
Updated
When clicking hideRow action, I access the dataItem as follows.
function hideRow(e) {
e.preventDefault();
var dataItem = this.dataItem($(e.currentTarget).closest("tr"));
if (dataItem.IsActive == true) {
dataItem.IsActive = false;
}
else {
dataItem.IsActive = true;
}
}
Is there any possible way to access data from template function as above or any other way?
I would suggest a different approach because you can't access grid data while rendering and populating grid.
My suggestion is to use two actions and hide it based on the flag (in your case IsActive).
Something like this: Custom command
NOTE: in visible function you can access item!
EDIT: you can access it and change it on dataBound traversing through all data.
Check this example: Data bound
I don't see the advantage of relying on the grid commands. You can render any button you want yourself and and use the dataBound event to bind a click handler:
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{
template: function(dataItem) {
const isActive = dataItem.isActive;
return `<a title=${isActive ? "Hide": "Show"} class="k-grid-hideRow k-button"><span class="k-icon k-i-${isActive ? 'lock' : 'unlock'}"></span></a>`
}
}
],
dataBound: function(e) {
e.sender.tbody.find(".k-grid-hideRow").click(evt => {
const row = evt.target.closest("tr")
const dataItem = e.sender.dataItem(row)
dataItem.set("isActive", !dataItem.isActive)
})
},
dataSource: [{ name: "Jane Doe", isActive: false }, { name: "Jane Doe", isActive: true }]
});
Runnable Dojo: https://dojo.telerik.com/#GaloisGirl/eTiyeCiJ

Updating Div with Total Records Outside of table

I’m working with datatables and trying to figure out what I’m doing wrong. I am trying to display the total number of rows when the table hits the draw event on the table. Right now with the code, I’m showing below I am not getting any console errors. The element where the number is supposed to be updated is correct. I am just not getting it to render with the correct count.
("use strict");
const renderStatusCell = (data, type, full, meta) => {
const status = {
0: { title: "Inactive" },
1: { title: "Active" }
};
if (typeof status[data] === "undefined") {
return data;
}
return status[data].title;
};
var table = $('[data-table="users.index"]');
// begin first table
table.DataTable({
// Order settings
order: [[1, "desc"]],
ajax: "/titles",
columns: [
{ data: "id", title: "User ID" },
{ data: "name", title: "Name" },
{ data: "slug", title: "Slug" },
{ data: "introduced_at", title: "Date Introduced" },
{ data: "is_active", title: "Status", render: renderStatusCell },
{
data: "action",
title: "Actions",
orderable: false,
responsivePriority: -1
}
]
});
var updateTotal = function() {
table.on("draw", function() {
$("#kt_subheader_total").html(table.fnSettings().fnRecordsTotal());
});
};
I expected when the table was rendered to update the dom with the correct number of rows however the div does not get updated.
I don't understand your problem, but I think you need something like that.
table
.row($(this).parents('tr'))
.remove()
.draw();
or
table.ajax.reload();
I believe you need to wait until the HTML loads before running all your javascript code. Also, if you are storing the total, you not make it a function but rather just store the value.
'use strict';
// this will make sure all the HTML loads before the JavaScript runs.
$(function() {
var table = $('[data-table="users.index"]');
var updateTotal = null; // store in a variable
const renderStatusCell = (data, type, full, meta) => {
const status = {
0: { title: "Inactive" },
1: { title: "Active" }
};
if (typeof status[data] === "undefined")
return data;
return status[data].title;
};
// begin first table
table.DataTable({
// Order settings
order: [[1, "desc"]],
ajax: "/titles",
columns: [
{ data: "id", title: "User ID" },
{ data: "name", title: "Name" },
{ data: "slug", title: "Slug" },
{ data: "introduced_at", title: "Date Introduced" },
{ data: "is_active", title: "Status", render: renderStatusCell },
{
data: "action",
title: "Actions",
orderable: false,
responsivePriority: -1
}
]
});
table.on("draw", function() {
updateTotal = table.fnSettings().fnRecordsTotal();
$("#kt_subheader_total").html(table.fnSettings().fnRecordsTotal());
});
});

Sort Backbone Paginator Results on Server instead at Client

I use https://github.com/backbone-paginator/backbone.paginator to display data at a table whose columns are sortable. But when clicking on any header of a column, the sorting is done at the client instead of doing a new server request that should contain the attribute (e.g. name) that should be used to sort the results.
Base class
module.exports = Backbone.PageableCollection.extend({
initialize: function (items, options) {
options || (options = {});
this.url = options.url || "/";
},
state: {
pageSize: 15,
firstPage: 0,
currentPage: 0
},
queryParams: {
sortKey: 'sort',
pageSize: 'size',
currentPage: 'page'
},
parseState: function (resp) {
return {totalRecords: resp && resp.length > 0 ? resp[0]['total_entries'] : 0};
},
parseRecords: function (resp) {
return resp && resp.length > 0 ? resp[1] : [];
},
model: Backbone.NestedModel
});
Example Instantiation
collections.myTasks = new collections.PagingCollection([], {
model: models.SyncModel.extend({
url: URLs.TASKS
}),
url: URLs.MY_TASKS,
state: {
pageSize: 30,
firstPage: 0,
currentPage: 0,
}
});
Columns
columns: [
{
name: "dueDate",
label: "Due Date",
cell: "date",
filterCell: FilterCell,
editable: false,
width: "80px"
},
{
name: "reminder",
label: "Reminder",
filterCell: FilterCell,
cell: Backgrid.StringCell.extend({
formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
fromRaw: function (rawValue, model) {
return DateHelper.format(
IntervalHelper.calculateBefore(model.attributes['dueDate'], rawValue)
);
}
})
}),
editable: false,
width: "80px"
},
{
name: "name",
label: "Subject",
cell: "string",
filterCell: FilterCell,
editable: false,
width: "auto"
},
{
name: "taskStatusCtlg.taskStatus",
label: "State",
filterCell: SelectFilterCell.extend({
filterField: 'taskStatus',
addAllOption: true
}),
cell: "string",
width: "75px"
},
{
name: "assignedTo.alfrescoUserName",
label: "Assigned To",
cell: "string",
filterCell: SelectFilterCell.extend({
filterField: 'assignee',
addAllOption: true
}),
editable: false,
width: "120px"
},
{
name: "taskTypeCtlg.taskType",
label: "Type",
cell: "string",
filterCell: SelectFilterCell.extend({
filterField: 'taskType',
addAllOption: true
}),
editable: false,
width: "70px"
},
{
name: "mainDocument.name",
label: "Case / Document",
link: "mainDocument.id",
cell: LinkCell,
filterCell: FilterCell,
editable: false,
width: '160px'
}
],
Fetching the data etc. is done without problems. But when clicking on a caret sorting is done on the client. But I need that attributes "sort" and "order" get append to the request URL when clicking on a column header (sorting on the server).
Current request:
http://localhost/tasks/user?page=0&size=30
Needed request:
http://localhost/tasks/user?page=0&size=30&sort=name&order=asc
Paginator offers 3 modes for the fetching and sorting:
client: all on the client. Feed the data yourself.
server: Fetch the data from an API (e.g.: collection.getFirstPage()) and receive the total number of pages.
infinite: like the server mode, but best used with unknown number of pages. Like a search result from an external API.
Ensure that you're using the server value for the mode property on the PageableCollection.
var books = new Books([
{ name: "A Tale of Two Cities" },
{ name: "Lord of the Rings" },
// ...
], {
// Paginate and sort on the server side, this is the default.
mode: "server",
});
or within your collection class definition:
module.exports = Backbone.PageableCollection.extend({
mode: "server", // this is the default
initialize: /*...*/
Other than that, this is likely solvable within Backgrid.
The default of Backgrid is to sort on the client. For a custom behavior, you can
provide a Backbone.PageableCollection
or override the HeaderCell view with your own implementation
Using a Backbone.PageableCollection
Set the collection property of the Grid.
var taskGrid = new Backgrid.Grid({
collection: collections.myTasks,
columns: [/*...*/],
});
Overriding the HeaderCell view
You are allow to use a different header cell class on columns. There is no restriction on what a header cell must do. In fact, any Backbone.View class can be used. However, if you wish to modify how the sorter behaves, you must
implement the sorting protocol. See the JSDoc for details.
var SelectAllHeaderCell = Backgrid.HeaderCell.extend({
// Implement your "select all" logic here
});
var grid = new Backgrid.Grid({
columns: [{
name: "selected",
label: "",
sortable: false,
cell: "boolean",
headerCell: SelectAllHeaderCell
}],
collection: col
});
Note (2017/01/30): Links to the API documentation within the documentation are not up to date, this is being discussed in issue #664.

jqGrid doesn't read JSON without square brakcets

I used this code for APIs that were surrounded with square brackets and it worked. However, it doesn't work for an API that looks like this:
{"name":"Summer Tire","description":"Premium Summer Tires.","notes":"Good price","supplier":"Tire Systems","price":79,"currency":"EUR","ID":2}
Here is my code:
function loadMaterialDetails(id) {
$("#materialDetails").jqGrid("GridUnload");
$("#materialDetails").jqGrid({
url: url,
mtype: "GET",
datatype: "json",
colModel: [
{ label: 'Material ID', name: 'ID', key: true, width: 1 },
{ label: 'Material Name', name: 'name', width: 2 },
{ label: 'Supplier', name: 'supplier', width: 2 },
{ label: 'Description', name: 'description', width: 3 },
{ label: 'Notes', name: 'notes', width: 1 },
{ label: 'Price', name: 'price', width: 1 },
{ label: 'Currency', name: 'currency', width: 1 }
],
viewrecords: true,
width: 780,
height: 250,
rowNum: 20,
onSelectRow: function(id){
alert(id);
}
});
UPDATE
I gave up on it. If I know that only one row could ever be acquired I fetch it with getJSON and manipulate it manually. Thanks for you input guys!
While Oleg's answer works, it is incomplete.
Try this:
jsonReader: {
root: function (obj) {
return obj instanceof Array ? obj : [obj];
}
}
This will ensure that the grid will continue to work when the returned data is an array of rows, while also allowing it to render the single row / object.
Everything is possible. You need to add jsonReader with root defined as function:
jsonReader: {
root: function (obj) {
return [obj];
}
}
See the demo https://jsfiddle.net/OlegKi/kLsqk8gc/ which displays the results like
UPDATED: I forget to add small changes posted before in the discussion, which is deleted now. If the response in not always object, but could be correct (array too) then one can just use:
jsonReader: {
root: function (obj) {
return $.isArray(obj) ? obj : [obj];
}
}

Remote Filtering with ListFilter in ExtJS Grid Column Header

I am using ListFilter plugin to filter results on a Grid panel. The column definition is.
{
header: 'Provider',
filter: {
type: 'list',
store: Ext.getStore('MyApp.store.Provider'),
dataIndex: 'provider_id',
labelField: 'name'
}
}
MyApp.store.Provider is created as
Ext.create('Ext.data.Store', {
storeId: 'MyApp.store.Provider',
autoDestroy: true,
autoLoad: {start: 0, limit: 50},
autoSync: true,
model: 'MyApp.model.Provider',
pageSize: 50,
proxy: {
type: 'ajax',
api: {
create: 'proxy/provider/create',
read: 'proxy/provider/read',
update: 'proxy/provider/update',
destroy: 'proxy/provider/destroy'
},
reader: {
type: 'json',
root: 'data',
successProperty: 'success',
messageProperty: 'message',
totalProperty: 'total'
},
writer: {
allowSingle: false,
type: 'json',
writeAllFields: false,
root: 'data'
}
}
});
And lastly model MyApp.model.Provider is defined as
Ext.define('MyApp.model.Provider', {
extend: 'Ext.data.Model',
fields: [
{ name: 'provider_id', type: 'int'},
'name',
{ name: 'create_time', type: 'date', dateFormat: appDateFormat },
{ name: 'status', type: 'int'}
],
idProperty: 'provider_id',
displayProperty: 'name' // A custom property used for dynamically use the property to display
})
Now this code does not show any sub-menu in the filter menu. It just shows loading. See the image.
Update
I have solved it using following filter config. This actually populates options config manually. So no store is used here.
{
type: 'list',
labelField: 'name',
options: (function () {
var opts = [];
fS.load(function (records, operation, success) {
for (var i = 0; i < records.length; i++) {
var ar = {
id: records[i].get('provider_id'),
name: records[i].get('name')
};
opts.push(ar);
}
});
return opts;
})(),
single: true
}
It seems 'id' is hard-coded. id: records[i].get('provider_id'), does not look good. Though it works.
But I am still looking for a proper way to do it.
Note: The expected behavior can be found on ExtJS 4.1.1. See this jsfiddle. I have reproduced it. But this very same thing does not work on ExtJS 4.0.7
I didn't tried this myself but you need to set the ID manually with the idField property [new to ExtJS4.1.3] which is per default set to id. So I guess this will work:
{
header: 'Provider',
filter: {
type: 'list',
idField: 'provider_id',
store: Ext.getStore('MyApp.store.Provider'),
dataIndex: 'provider_id',
labelField: 'name'
}
}
Update
OK, I looked at the source and I can now tell you that this is the answer. So will have to either live with your workarround until 4.2 is out or you can apply the following changes to your Ext.ux.grid.menu.ListMenu to make it run:
add the idField with a default value.
look within the constructor for this lines
case 'object': options.push([value.id, value[this.labelField]]); break;
// some more lines
fields: ['id', this.labelField],
and replace it with
case 'object': options.push([value[me.idField], value[me.labelField]]); break;
// some more lines
fields: [me.idField, me.labelField],
and within the onLoad function look for
itemValue = records[i].get('id');
and replace it with
itemValue = records[i].get(me.idField);
and that pretty much is it.

Categories