How can I set or change a value of a concrete cell programmatically? - slickgrid

Using a pure array as data source (not a DateView) to initialize a SlickGrid, I want to change a value after grid creation on a specific row / column (a cell).
Here is the simple example, that can also be found as a working JSFiddle and I want for example to change the value of "Duration" on row 3 ("Task 2") from "5 days" to "7 days".
<div id="myGrid" style="width:400px;height:400px;"></div>
<script>
var grid;
var columns = [
{id: "title", name: "Title", field: "title"},
{id: "duration", name: "Duration", field: "duration"},
{id: "%", name: "% Complete", field: "percentComplete"},
{id: "start", name: "Start", field: "start"},
{id: "finish", name: "Finish", field: "finish"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven"}
];
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
$(function () {
var data = [];
for (var i = 0; i < 500; i++) {
data[i] = {
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
}
grid = new Slick.Grid("#myGrid", data, columns, options);
grid.setSelectionModel(new Slick.CellSelectionModel());
/* needed method */
grid.setCellValue(2, 1, "7 days");
/* or */
grid.setCellValue(2, "duration", "7 days");
})
</script>
It looks like a method like
grid.setCellValue(row, column, value);
does not exist.
Is there a way (or existing method I didn't found yet) to achieve this without using a DataView?

Just use
data[2].duration = "7 Days";
and then refresh the grid:
grid.invalidateAllRows();
grid.render();
The grid only has display related helper methods, although you can get the data with grid.getData(). Editors, if you use them, contain code to extract the value from a row (data[n]) and write it to the editor UI, and then go back the other way.

Related

Kendo UI Grid: select entire column

The code below selects the first cell in a grid, but how can I select the entire column (either the first or second column)?
HTML:
<div id="grid"></div>
Javascript:
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: [
{ name: "Jane Doe", age: 30 },
{ name: "John Doe", age: 33 }
],
selectable: "cell"
});
var grid = $("#grid").data("kendoGrid");
grid.select("td:eq(0)"); // <--- selects the first cell
This is how you do it:
grid.select("td:eq(" + cell1 + "), td:eq(" + cell2 + "), td:eq(" + cell3 + ")");
where cell1, cell2 and cell3 are the indexes of the cells that comprise the column. You need to calculate these indexes depending on the number of columns; kendo counts these cells horizontally.

Kendo Grid - In Firefox triggering an alert in the save event causes a page reload

I want to know if anyone has seen this. I have a kendo grid and in the save event, I want to do some validation. Basically to make sure that the new values difference between the old is less than or equal to the balance.
So if it is greater than the balance, I trigger an alert and preventDefault. However displaying an alert causes the page to reload in FireFox.
Here is my grid:
$("#gridOpenInvoices").kendoGrid({
autoBind: false,
dataSource: openInvoicesData,
scrollable: true,
sortable: false,
navigatable: true,
toolbar: [{name:"save",
text:strings.ApplyUpdates},
{name: "SplitPayment",
text: strings.SplitPayment},
{name: "PaidOut",
text: strings.PaidOut},
{name: "CreateCredit",
text: strings.CreditBalance},
{name: "UndoAllocation",
text: strings.UndoAllocation}],
columns: [
{
field: "CustomerName",
title: strings.AccountName,
hidden: true
},
{
field: "OpenTransactionId",
title: strings.OpenTransaction,
width:90
},
{
field: "InvoiceNumber" ,
title: strings.InvoiceNumber,
width:65
},
{
field: "GrossSales",
title: strings.OriginalAmount,
width: 75,
format: "{0:c}",
decimals: 2,
min: 1,
value: 0
},
{
field: "Balance",
title: strings.TransBalance,
width: 75,
format: "{0:c}",
decimals: 2,
min: 1,
value: 0
},
{
field: "Date",
title: strings.Date,
width:75,
format: "{0:MM/dd/yy}"
},
{
field: "Age",
title: strings.Age,
width:55
},
{
field: "CheckNumber",
title: strings.CheckNumber,
width:85
},
{
title: strings.ApplyPayment,
width:75,
template: "<input class='k-chk-applied chkbox' type='checkbox' data-bind='source: IsApplied' name='IsApplied' #= IsApplied ? 'checked' : ''#/>",
attributes:{"class":"tdIsApplied"}
},
{
field:"AppliedAmount",
title: strings.AppliedAmount,
format: "{0:c}",
width: 95,
attributes: {"class" : "tdAppliedAmount"}
}],
save: function(e) {
var model = e.model;
if (e.values.AppliedAmount != null) {
var remainingBalance = context.getRemainingBalance();
var difference = e.values.AppliedAmount - model.AppliedAmount;
if (remainingBalance >= difference) {
var balanceCopy = model.BalanceCopy;
model.Balance = model.GrossSales - e.values.AppliedAmount;
model.BalanceCopy = model.GrossSales - e.values.AppliedAmount;
if (model.Balance == 0 && model.IsUncollected) {
model.IsUncollected = false;
context.UpdateBalance(balanceCopy, 0, true);
}
context.UpdateBalance(model.AppliedAmount, e.values.AppliedAmount, true);
this.refresh();
context.showButtons();
}
else {
alert("The applied amount exceeds the remaining balance");
e.preventDefault();
}
}
}, editable:"incell"});
This seems to be only happening when you edit the applied amount and hit enter to commit. Any idea of why this is happening?
The solution is fairly simple: Do not use an alert.
I do have the same problem in some events in kendoUI Widgets.
If you need to display something to the user, use kendoWindow with it's modal property set to true.
Alerts should only be used for debugging purposes, like console.log.

Add to kendoMultiSelect

With the new kendo multiselect how would I add options to the list and make them selected?
For instance if I have a dropdown containing: 1,2,3 and I wanted to add 4 and 5 how do I do that? Do I have to destroy the multiselect, add the options and then reinit the multiselect?
Given the following multiselect definition:
var data =
[
{ text: "Africa", value: "1" },
{ text: "Europe", value: "2" },
{ text: "Asia", value: "3" },
{ text: "North America", value: "4" },
{ text: "South America", value: "5" },
{ text: "Antarctica", value: "6" },
{ text: "Australia", value: "7" }
];
var multi = $("#select").kendoMultiSelect({
dataTextField: "text",
dataValueField: "value",
dataSource: data
}).data("kendoMultiSelect");
You can use:
var values = multi.value();
For getting the list of values.
And for setting the value to South America (element with value 5) and "Asia" (element with value 3) use:
multi.value(["5", "3"])
If you want to add values to whatever it has then you need a little trick:
var multi = $("#select").kendoMultiSelect({
dataTextField: "text",
dataValueField: "value",
dataSource: data,
value: ["1", "2", "3"]
}).data("kendoMultiSelect");
// Adding value 4 and 5 to current content
var values = multi.value().slice();
$.merge(values, ["4", "5"]);
multi.value(values);
Warning: If values 4 and 5 were already selected you will end up having them duplicated.
Just want to add some information about how to actually add new values to the multi-select.
As OnaBai points out, the code to add an item to the multi-select is
$("#SDropDown").data("kendoMultiSelect").dataSource.add({ Text: x, Value: y });
given the .cshtml
#(Html.Kendo()
.MultiSelect()
.Name("SDropDown")
.AutoBind(true)
.Placeholder("Select s...")
.DataTextField("Text")
.DataValueField("Value")
)
In order to add an item as entered in the multi-select hook the change event for the text input. Since this isn't uniquely identified, I use XPath to get the <input> element. This is hooked in document.ready (in .cshtml, so escape #):
$(document).ready(function () {
var node = document.evaluate('//select[##id="SDropDown"]/../div[contains(##class,"k-multiselect")]/input', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
if (node)
{
node.onkeypress = SChanged;
}
}
function SChanged(e)
{
// only append on enter
if (kendo.keys.ENTER == e.keyCode)
{
// updates multi-select data source
AddToOrganizations(this.value);
var multi = $("#SDropDown").data("kendoMultiSelect");
multi.dataSource.filter({}); //clear applied filter before setting value
// keep all currently selected items and append the user entered text
// (does not check for duplicates)
// Also, the new values can only be selected after the data source has
// been updated.
var values = multi.value().slice();
$.merge(values, [this.value]);
multi.value(values);
}
}

jqGrid : Get data from a row that has been clicked within a heirarchical grid

Im currently working on a project which uses jqGrid with multiple subgrids. I'm trying to get the rowid (and get at the data within the row) when a row is clicked or double clicked. Eventually I would like to fill a text box with data from a clicked row.
I've tried a few variations using ondblClickRow and onSelectRow examples on here but wans't able to get it working. I think I'm missing something really simple but don't see what. So I went back and simplified it down as much as possible to just recognize the row click and display an alert. This won't work for me either.
(based on the example in jqGrid : issue loading nested sub grid with local datatype) Look for the //***************
part near the bottom..
var myData = [
// main grid data
{ id: "1", col1: "11", col2: "12",
subgrid: [
// data for subgrid for the id=m1
{ id: "1", c1: "aa", c2: "ab", c3: "ac",
subgrid: [
// data for subgrid for the id=m1, subgridId=s1a
{ id: "1", d1: "2aa", d2: "2ab", d3: "2ac" },
{ id: "2", d1: "2ba", d2: "2bb", d3: "2bc" },
{ id: "3", d1: "2ca", d2: "2cb", d3: "2cc" }
]},
{ id: "2", c1: "ba", c2: "bb", c3: "bc" },
{ id: "3", c1: "ca", c2: "cb", c3: "cc" }
]},
{ id: "2", col1: "21", col2: "22",
subgrid: [
// data for subgrid for the id=m2
{ id: "1", c1: "1xx", c2: "1xy", c3: "1xz",
subgrid: [
// data for subgrid for the id=m2, subgridId=s2a
{ id: "1", d1: "2xx", d2: "2xy", d3: "2xz" }
]}
]},
{ id: "3", col1: "31", col2: "32" }
],
removeSubgridIcon = function () {
var $this = $(this),
idPrefix = $this.jqGrid("getGridParam", "idPrefix");
$this.find(">tbody>tr.jqgrow>td.ui-sgcollapsed").filter(function () {
var rowData = $this.jqGrid("getLocalRow",
$.jgrid.stripPref(idPrefix, $(this).closest("tr.jqgrow").attr("id")));
return rowData.subgrid == null;
}).unbind("click").html("");
},
isHasSubrids = function (data) {
var l = data.length, i;
for (i = 0; i < l; i++) {
if (data[i].subgrid != null) {
return true;
}
}
return false;
},
specificGridOptions = [
{
colNames: ["Column 1", "Column 2"],
colModel: [
{ name: "col1" },
{ name: "col2" }
],
cmTemplate: { width: 200 },
sortname: "col1",
sortorder: "desc",
idPrefix: "s_",
pager: "#pager",
caption: "Demonstrate how to create subgrid from local hierarchical data"
},
{
colNames: ["Colunm1", "Colunm2", "Colunm3"],
colModel: [
{ name: "c1" },
{ name: "c2" },
{ name: "c3" }
],
cmTemplate: { width: 112 },
sortname: "c1",
sortorder: "desc"
},
{
colNames: ["Col 1", "Col 2", "Col 3"],
colModel: [
{ name: "d1" },
{ name: "d2" },
{ name: "d3" }
],
cmTemplate: { width: 90 },
sortname: "d1",
sortorder: "desc"
}
],
commonGridOptions = {
datatype: "local",
gridview: true,
rownumbers: true,
autoencode: true,
height: "100%",
//***************
onSelectRow : function ()
{
alert('test!');
},
//also tried many variation on this
ondblClickRow: function(rowid)
{
alert(rowid);
}
//***************
loadComplete: function () {
// one can use loadComplete: removeSubgridIcon, but I included
// curent implementation of loadComplete only to show how to call
// removeSubgridIcon from your loadComplete callback handler
removeSubgridIcon.call(this);
},
subGridRowExpanded: function (subgridDivId, rowId) {
var $subgrid = $("<table id='" + subgridDivId + "_t'></table>"),
subgridLevel = $(this).jqGrid("getGridParam", "subgridLevel") + 1,
parentIdPrefix = $(this).jqGrid("getGridParam", "idPrefix"),
pureRowId = $.jgrid.stripPref(parentIdPrefix, rowId),
localRowData = $(this).jqGrid("getLocalRow", pureRowId);
$subgrid.appendTo("#" + $.jgrid.jqID(subgridDivId));
$subgrid.jqGrid($.extend(true, {}, commonGridOptions, specificGridOptions [subgridLevel], {
data: localRowData.subgrid,
subGrid: isHasSubrids(localRowData.subgrid),
subgridLevel: subgridLevel,
idPrefix: rowId + "_",
rowNum: 10000 // we use this to have no pager in the subgrids
}));
}
};
$("#list").jqGrid($.extend(true, {}, commonGridOptions, specificGridOptions[0], {
data: myData,
subgridLevel: 0,
subGrid: isHasSubrids(myData)
}));
Anyone have any ideas why it won't recognize the row click/double click?
You wrote in comment that you get the data for the grid from the server. I suppose that the usage of datatype: "local" in the case is not the best choice. Look at the answer where I described the way how to do the same, but using datatype: "json".
Now I come back to your main question. I don't understand what text box (HTML input element) you want to fill and whether the input element is inside of the grid or outside of it. Nevertheless the only problem which you could probably have is the correct usage of idPrefix option of jqGrid.
It's very important to understand, that jqGrid use HTML <table> for representing of the body of grids. Every <tr> element of the <table> must have id attribute in the current implementation of jqGrid. So the id property from the input data will be used to assign the value of id attribute of <tr> elements. If one has more as one grid on the page or if one has grid with subgrids it's very easy to receive id duplicates which not allowed in all versions of HTML or XHTML.
Additional potential problem is the usage of numbers as id values. The most databases support auto-incremental datatype which is very practical as the key of the tables. In the case the native id (the key) for the database table and for the grid rows will be integer numbers. On the other side there are some additional restrictions depend on the version of HTML/XHTML which one uses. For example HTML5 specification says (see here)
The value must be unique amongst all the IDs in the element's home
subtree and must contain at least one character. The value must not
contain any space characters.
So even though the most web browsers allows to use numbers as the values of id attribute it's not permitted and one can get compatibility problems in case of usage of this.
To solve all the described above problem jqGrid supports idPrefix options (which was introduced by the way based on my suggestion). In the case the value of id attribute will be build as concatination of idPrefix and the id from the input data. For example in case of idPrefix: "s_" and id values "1", "2", "3" used in the main grid of the example jqGrid will assign "s_1", "s_2", "s_3" as values of id attribute of <tr> elements of the main grid. The rowid of all callbacks will be the value from id attribute ("s_1", "s_2", "s_3"). If you need get the original id you can use $.jgrid.stripPref to strip the prefix. All ids which will be sent to the server by jqGrid will be normalized ($.jgrid.stripPref will be called) by jqGrid itself.
So the code which shows how to get data onSelectRow and ondblClickRow could be the following
onSelectRow: function (rowid, stat, e) {
myDebugTrace.call(this, "onSelectRow", rowid);
},
ondblClickRow: function (rowid, iRow, iCol, e) {
myDebugTrace.call(this, "ondblClickRow", rowid);
e.stopPropagation();
},
...
where myDebugTrace function can be declared as
var myDebugTrace = function (startingText, rowid) {
var $this = $(this), p = $this.jqGrid("getGridParam"), rowData, col1,
firstCol = (p.rownumbers ? 1 : 0) + (p.subGrid ? 1 : 0);
rowData = $this.jqGrid("getRowData", rowid);
col1 = rowData[p.colModel[firstCol].name];
$("<span>" + startingText + " on " + rowid + " (original id=" +
$.jgrid.stripPref($(this).jqGrid("getGridParam", "idPrefix"), rowid) +
"). Data from the first column: \"" + col1 +"\"</span><br/>").appendTo("body");
};
The corresponding demo display the following on double-click on the row from the internal subgrid.

Add data to DataView SlickGrid

I want add data to DataView in SlickGrid and I have a code:
var columns = [
{id: "title", name: "Title", field: "title"},
{id: "duration", name: "Duration", field: "duration"},
{id: "%", name: "% Complete", field: "percentComplete"},
{id: "start", name: "Start", field: "start"},
{id: "finish", name: "Finish", field: "finish"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven"}
];
$(document).ready(function() {
for (var i = 0; i < 200; i++) {
data[i] = {
id: "id_" + i,
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
}
dataView = new Slick.Data.DataView({ inlineFilters: true });
grid = new Slick.Grid("#myGrid", dataView, columns, options);
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(filter);
dataView.endUpdate();
});
But I see only scrollbars and column headers, but I don't see any data, why?
Try this,
var columns = [
{id: "title", name: "Title", field: "title"},
{id: "duration", name: "Duration", field: "duration"},
{id: "%", name: "% Complete", field: "percentComplete"},
{id: "start", name: "Start", field: "start"},
{id: "finish", name: "Finish", field: "finish"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven"}
];
$(document).ready(function() {
for (var i = 0; i < 200; i++) {
data[i] = {
id: "id_" + i,
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
}
dataView = new Slick.Data.DataView({ inlineFilters: true });
grid = new Slick.Grid("#myGrid", dataView, columns, options);
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(filter);
dataView.endUpdate();
dataView.render(); //You missed this rendering part. this should work now.
});
Try this
var data = [];
var options = {};
var columns = [
{id: "title", name: "Title", field: "title"},
{id: "duration", name: "Duration", field: "duration"},
{id: "%", name: "% Complete", field: "percentComplete"},
{id: "start", name: "Start", field: "start"},
{id: "finish", name: "Finish", field: "finish"},
{id: "effort-driven", name: "Effort Driven", field: "effortDriven"}
];
$(document).ready(function() {
for (var i = 0; i < 200; i++) {
data[i] = {
id: "id_" + i,
title: "Task " + i,
duration: "5 days",
percentComplete: Math.round(Math.random() * 100),
start: "01/01/2009",
finish: "01/05/2009",
effortDriven: (i % 5 == 0)
};
}
dataView = new Slick.Data.DataView({ inlineFilters: true });
dataView.beginUpdate();
dataView.setItems(data);
dataView.endUpdate();
grid = new Slick.Grid("#myGrid", dataView, columns, options);
});

Resources