KendoGrid inline editing with dynamic drop down lists - kendo-ui

In this demo, if you click on the category, you'll see a dropdown list to choose the value. What I need is to have the values of the dropdown list depend on a condition, so when you open the dropdown list on different rows you may get different lists.
At the moment I create a row, I have the values to populate the dropdown list, but I'm not sure how to use these values.
This is how I defined the column (I won't be using a template):
{ field: "source", title: "Source", width: "180px", editor: srcEditor},
And this is the editor:
function srcEditor(container, options) {
$('<input required data-text-field="name" data-value-field="id"
data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
dataSource: sources,
dataTextField: "name",
dataValueField: "id"
});
}
This only works if all the rows have the same dropdown list, but how can I declare a different srcEditor for each row?

By this statement :
declare a different srcEditor for each row
You either mean to have
entirely different datasource for each row,
having same datasource but do some filter if certain condition meet, or
differ in styling (for this one simply add class/style)
Solution for number 1 modify your categoryDropDownEditor function, do some conditional to set the url for the datasource and add the different url :
function categoryDropDownEditor(container, options) {
var model = options.model;
var tempDataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: ( (model.UnitPrice > 20) ? urlConst.restServiceA : urlConst.restServiceB),
}
});
}
Solution for number 2 modify your categoryDropDownEditor function and add your condition and do (sor/filter) on parameter map, here's link :
function categoryDropDownEditor(container, options) {
var model = options.model;
var tempDataSource = new kendo.data.DataSource({
type: "odata",
transport: {
read: "http://demos.telerik.com/kendo-ui/service/Northwind.svc/Categories",
parameterMap: function (options, operation) {
console.log("test",operation,operation);
if (operation == "read" && options) {
//do your condition here
if(model.UnitPrice > 20){
tempDataSource.filter({field:"CategoryName", operator:"eq", value: "Condiments"});
}
return kendo.data.transports["odata"].parameterMap(options, operation);
}
}
},
});

Related

What causes jqgrid events to fire multiple times?

Our jqgrid is configured in an initgrid function that is called as the last statement of a ready handler. For some reason, the gridcomplete function is getting called multiple times. With the code below, it gets called twice, but it had been getting called 3 times. Twice is bad enough. After stepping through it multiple times, I don't see what is triggering the second execution of the gridComplete function.
When I hit the debugger at the start of gridComplete, the call stack is virtually identical each time, the only difference being a call to 'L' in the jqgrid:
Anyone have an idea why this is occurring? We are using the free version 4.13, in an ASP.net MVC application.
$(function(){
....
initGrid();
}
function initGrid(){
$gridEl.jqGrid({
xhrFields: {
cors: false
},
url: "/IAConsult/GetWorkFlowIARequests",
postData: {
showAll: showAllVal,
role: role,
IsIAArchitect: userIsIA
},
datatype: "json",
crossDomain: true,
loadonce: true,
mtype: 'GET',
sortable: true,
viewrecords: true,
pager: '#workFlowIAGridPager',
multiselect: true,
rowNum: 50,
autowidth: true,
colModel: [...],
beforeSelectRow: function (rowid, e) {
var $myGrid = $(this),
i = $.jgrid.getCellIndex($(e.target).closest('td')[0]),
cm = $myGrid.jqGrid('getGridParam', 'colModel');
return (cm[i].name === 'cb');
},
jsonReader: {
repeatitems: true,
root: "IAConsultWorkflowRequestsList"
},
beforeSubmitCell: function (rowid, name, value, iRow, iCol) {
return {
gridData: gridData
};
},
serializeCellData: function (postdata) {
return JSON.stringify(postdata);
},
gridComplete: function () {
console.log('grid complete');
let rowIDs = $gridEl.getDataIDs();
let inCompleteFlag = false;
let dataToFilter = $gridEl.jqGrid('getGridParam', 'lastSelectedData').length == 0
? $gridEl.jqGrid("getGridParam", "data")
: $gridEl.jqGrid('getGridParam', 'lastSelectedData');
let $grid = $gridEl, postfilt = "";
let localFilter = $gridEl.jqGrid('getGridParam', 'postData').filters;
let columnNames = columns.split(',');
$('.moreItems').on('click', function () {
$.modalAlert({
body: $(this).data('allitems'),
buttons: {
dismiss: {
caption: 'Close'
}
},
title: 'Design Participants'
});
});
rowCount = $gridEl.getGridParam('records');
gridViewRowCount = rowCount;
let getUniqueNames = function (columnName) {
... };
let buildSearchSelect = function (uniqueNames) {
var values = {};
values[''] = 'All';
$.each(uniqueNames,
function () {
values[this] = this;
});
return values;
};
let setSearchSelect = function (columnName) {
...
};
function getSortOptionsByColName(colName) {
...
}
$grid.jqGrid("filterToolbar",
{ stringResult: true, searchOnEnter: true });
if (localFilter !== "" && localFilter != undefined) {
globalFilter = localFilter;
}
let grid = $gridEl.jqGrid("setGridParam",
{
postData: {
"filters": globalFilter,
showAll: showAllVal,
role: role,
IsIAArchitect: userIsIA
},
search: true,
forceClientSorting: true
});
//grid.trigger("reloadGrid");
//Ending Filter code
for (i = 0; i < columnNames.length; i++) {
var htmlForSelect = '<option value="">All</option>';
var un = getUniqueNames(columnNames[i]);
var $select = $("select[id='gs_workFlowIAGrid_" + columnNames[i] + "']");
for (j = 0; j < un.length; j++) {
val = un[j];
htmlForSelect += '<option value="' + val + '">' + val + '</option>';
}
$select.find('option').remove().end().append(htmlForSelect);
}
debugger;
},
// all grid parameters and additionally the following
loadComplete: function () {
$gridEl.jqGrid('setGridWidth', $(window).width(), true);
$gridEl.setGridWidth(window.innerWidth - 20);
},
height: '100%'
});
I personally almost never use gridComplete callback. It exists in free jqGrid mostly for backwards compatibility. I'd recommend you to read the old answer, which describes differences between gridComplete and loadComplete.
Some additional advices: it's dangerous to register events inside of callbacks (see $('.moreItems').on('click', ...). If you need to make some actions on click inside of grid then I'd recommend you to use beforeSelectRow. Many events, inclusive click event supports event bubbling and non-handled click inside of grid will be bubbled to the parent <table> element. You use already beforeSelectRow callback and e.target gives you full information about clicked element.
I recommend you additionally don't use setGridParam method, which can decrease performance. setGridParam method make by default deep copy of all internals parameters, inclusive arrays like data, which can be large. In the way, changing one small parameter with respect of setGridParam can be expensive. If you need to modify a parameter of jqGrid then you can use getGridParam without additional parameters to get reference to internal object, which contains all jqGrid parameters. After that you can access to read or modify parameters of jqGrid using the parameter object. See the answer for example for small code example.
Also adding the property
loadonce: true
might help.

How to select value programmatically with MagicSearch jQuery Plugin?

I am using this jQuery plugin MagicSearch
How can I programatically select a value (by ID for example)?
This is what I have. After a careful analysis of their callback functions, I have devised a method to extract the ID and Name from my search list.
Please find the code to my attempt:
<script>
var idList="";
var nameList = "";
$(function () {
var dataSource = "[{\"id\":1,\"name\":\"test\"},
{\"id\":2,\"name\":\"example\"},{\"id\":3,\"name\":\"image\"},
{\"id\":4,\"name\":\"election\"},{\"id\":5,\"name\":\"IPL\"},
{\"id\":6,\"name\":\"Fashion\"},{\"id\":7,\"name\":\"Movies\"},
{\"id\":8,\"name\":\"Pollution\"},{\"id\":9,\"name\":\"Modi\"},
{\"id\":10,\"name\":\"Rahul\"},{\"id\":11,\"name\":\"Cricket\"},
{\"id\":12,\"name\":\"Market\"},{\"id\":13,\"name\":\"TestKeyword\"},
{\"id\":14,\"name\":\"testkeyword1\"},{\"id\":15,\"name\":\"testkeyword2\"},
{\"id\":16,\"name\":\"testkeyword3\"}]";
$('#basic').magicsearch({
dataSource: dataSource,
fields: ['name'],
id: 'id',
format: '%name%',
hidden: true,
multiple: true,
focusShow: true,
isClear: true,
multiField: 'name',
multiStyle: {
space: 5,
width: 200
},
success: function ($input, data) {
idList = idList + data.id + ',';
nameList = nameList + data.name + ',';
// alert(data.id);
return true;
},
afterDelete: function ($input, data) {
idList = idList.replace(data.id + ',', "");
nameList = nameList.replace(data.name + ',',"");
//alert(data.id);
return true;
}
});
});
Link to the fiddle: https://jsfiddle.net/yn0cmgjt/5/
Excuse me for the bad interface. I had a difficult time getting the CDN link to this plugin and somehow it is not rendering the correct way. But play around with this and I hope it will suffice to your needs.
The two lists (idList and nameList) that I have created are the id and name for each element concatenated in a single comma separated string. Once you have this string, you can extract out the required information.

kendo multiselect values disappear when in editor mode

I have a master-child setup and in my child grid rows, I have a multi-select that uses a list of strings as datasource. When I click to add/remove entries, the already selected items disappear completely and I can only see the drop down with all the values.
Here is the grid column definition in the child grid:
field: "Teams",
title: "Team",
editor: ChildItemEditor,
Here is the editor function that creates the multi-select:
...
var dataSource = ["Item A" , "Item B"];
...
function ChildItemEditor(container, options)
{
$('<select multiselect="multiselect" id="ddlItems" name="childItems" data-bind="value:' + options.field + '" />')
.appendTo(container)
.kendoMultiSelect({
autoBind: false,
dataSource: dataSource,
select: function (e) {
var dataItem = this.dataItem(e.item.index());
var selectedItem = this.gridMasterData.dataItem(this.gridMasterData.select());
if (selectedItem == null) {
return false;
}
options.model.Items = this.value();
$(selectedItem.Items).each(function (i, cItem) {
if (options.model.Id == cItem.Id) {
cItem.Items= options.model.Items;
selectedItem.dirty = true
}
});
},
});
}
Found the issue: When reading back data, the second field had a leading space and Multiselect did not automatically Trim the field to bind to it.

Kendo Ui add on change action drop down list on grid column

I want to add onchange action for the drop down lists on this example:
http://demos.kendoui.com/web/grid/foreignkeycolumn.html
I need to send row id to this function.
If you see this example you can specify a custom editor for a column and do what ever you need in that method like this,
function categoryDropDownEditor(container, options) {
$('<input required data-text-field="CategoryName" data-value-field="CategoryID" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoDropDownList({
autoBind: false,
select: function(e) {
var item = e.item;
var text = item.text();
// Use the selected item or its text
},
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Categories"
}
}
});
}

How to get row index and cell index of row click kendo grid

I have added onchange event for kendo-ui grid.
In that I am trying to get the ID value for that particular row. I have added an image column as first column in the grid. What I want is when the image is clicked, I want to open a image url.
So, basically what I want is that when I click the row, I want to get the clicked row index and also I want to get the clicked cell Index in that row.
So based on the row clicked and if it is not the first cell clicked, I want to display alert. If I the first cell is clicked I want to open image.
How can I get this index.
I have set selectable : row in the kendo-ui grid
Please help me on this.
Please try with below code snippet.
function onDataBound(e) {
var grid = $("#Grid").data("kendoGrid");
$(grid.tbody).on("click", "td", function (e) {
var row = $(this).closest("tr");
var rowIdx = $("tr", grid.tbody).index(row);
var colIdx = $("td", row).index(this);
alert(rowIdx + '-' + colIdx);
});
}
$(document).ready(function () {
$("#Grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.kendoui.com/service/Northwind.svc/Orders",
dataType: "jsonp"
},
schema: {
model: {
fields: {
OrderID: { type: "number" },
Freight: { type: "number" },
ShipName: { type: "string" },
OrderDate: { type: "date" },
ShipCity: { type: "string" }
}
}
},
pageSize: 10,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
dataBound: onDataBound,
filterable: true,
sortable: true,
pageable: true,
columns: [{
field: "OrderID",
filterable: false
},
"Freight",
{
field: "OrderDate",
title: "Order Date",
width: 120,
format: "{0:MM/dd/yyyy}"
}, {
field: "ShipName",
title: "Ship Name",
width: 260
}, {
field: "ShipCity",
title: "Ship City",
width: 150
}
]
});
});
<div id="Grid"></div>
If all you need is knowing the row and column index in the table you can do:
$(grid.tbody).on("click", "td", function(e) {
var row = $(this).closest("tr");
var rowIdx = $("tr", grid.tbody).index(row);
var colIdx = $("td", row).index(this);
console.log("row:", rowIdx, "cell:", colIdx);
});
Where I set a click handler for clicking in the cells of the grid.
Then I find to which row (<tr>) that cell belongs to using jQuery closest.
Next use jQuery index for finding the index of that row in the table.
Do the same for finding the cell index inside the row.
But maybe there are simpler ways as detecting if the user clicked on an image, or set some CSS class in the image and then check if the clicked cell has that class,...
EDIT If in addition you want to retrieve the original item inside the click handler. Add
var item = grid.dataItem(row);
From there, you can get id or any other field for validation.
Example here : http://jsfiddle.net/OnaBai/MuDX7/
Kendo has introduced frozen columns since the question has been answered so I think it deserved a little update to deal with that feature.
When you have a frozen column, the grid will create new header / content tables to manage the frozen columns. If you freeze a column, it will move item linked to this column from the regular grid's tbody / thead to the lockedContent / lockedHeader (the opposite is also true).
If you get the index using the accepted answer, you'll get the index of the cell within the tbody (or -1 if the cell is frozen). The real question is what do you want to do with the column index? If you really want an index number, you may have to adjust the value by adding the number of columns in the lockedContent depending on your needs. However, if your final goal is to get the grid's column object, this can be done by using the th element:
var row = cell.closest("tr");
var body;
var header;
if (cell.closest(grid.lockedContent).length) {
body = grid.lockedContent;
header = grid.lockedContent;
} else {
body = grid.tbody;
header = grid.thead;
}
var rowIndex = $("tr", body).index(row);
var columnIndex = $("td", row).index(cell);
var columnField = header.find("th").eq(columnIndex).attr("data-field");
var column;
$.each(grid.columns, function () {
if (this.field === columnField) {
column = this;
return false;
}
});
Disclaimer: just to add a level of complexity, you should also consider that kendo has also introduced a multiple column header feature that may invalidate my code above.
For the cell index, kendo grid has a method cellIndex(cell)
var cell = $("#grid td:eq(1)");
console.log(grid.cellIndex(cell));

Resources