#Oleg - I am new to jqGrid.I have three issues. Urgent help required.
I am using jqGrid 3.8, inline edit mode.
I want to retain the invalid cell values after the pop up for invalid cell.
Also I want to set the focus back to the invalid cell.
I have "add row" and filter tool bar feature in my jqGrid. I have used Oleg's solution in creating drop down for filter tool bar (posted in another jQuery thread).
**
- Problem:
** I am calling setSearchSelect from afterSaveCell, because I want to add new values in filter drop down every time I add or delete column.(Note: column is a textbox). But the filter tool bar isn't getting refreshed even if I use
var sgrid = $("#list")[0];
sgrid.triggerToolbar();
See the code below for setting the toolbar.
<script type="text/javascript">
var mydata = [
{id:"1", Name:"Miroslav Klose", Category:"sport", Subcategory:"football"},
{id:"2", Name:"Michael Schumacher", Category:"sport", Subcategory:"formula 1"},
{id:"3", Name:"Albert Einstein", Category:"science", Subcategory:"physics"},
{id:"4", Name:"Blaise Pascal", Category:"science", Subcategory:"mathematics"}
],
grid = $("#list"),
getUniqueNames = function(columnName) {
var texts = grid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
},
buildSearchSelect = function(uniqueNames) {
var values=":All";
$.each (uniqueNames, function() {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function(columnName) {
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value:buildSearchSelect(getUniqueNames(columnName)),
sopt:['eq']
}
}
);
};
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name:'Name', index:'Name', width:200 ,editable:true},
{ name:'Category', index:'Category', width:200,editable:true },
{ name:'Subcategory', index:'Subcategory', width:200,editable:true }
],
sortname: 'Name',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
editurl: "clientArray",
multiselect: true,
pagination:true,
cellEdit: true,
cellsubmit: 'clientArray',
//ignoreCase: true,
pager: '#pager',
height: "auto",
enableSearch: true,
caption: "How to use filterToolbar better locally",
afterSaveCell: function(rowid,name,val,iRow,iCol) {
setSearchSelect(name);
jQuery("#list").('setColProp', name,
{
width:100
}
);
var sgrid = $("#list")[0];
sgrid.triggerToolbar();
alert(name);
},
loadComplete: function () {
setSearchSelect('Category');
}
}).jqGrid('navGrid','#pager',
{edit:false, add:false, del:false, search:false, refresh:true});
setSearchSelect('Category');
setSearchSelect('Subcategory');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt:['cn'],
dataInit: function(elem) {
$(elem).autocomplete({
source:getUniqueNames('Name'),
delay:0,
minLength:0
});
}
}
});
grid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"cn"});
function addRow(tableId){
var loopRow = document.getElementById("addRowsInput").value;
var recordCount = '';
var rwData = '';
//var selRowIds = getRowIDs('list');
var gridProducts = $("#list");
var resetFirstRow = jQuery("#list").getRowData( 1 );
jQuery("#list").setRowData( 1, resetFirstRow );
if(loopRow == null || loopRow == "" || loopRow == "Enter number of units to be added")
{
loopRow = 1;
}
for(i=0; i< loopRow; i++)
{
recordCount = jQuery("#list").getGridParam("records") ;
var emptydata = [
{id:(recordCount+1), Name:"", Category:"", Subcategory:""}]
gridProducts.jqGrid('addRowData', recordCount+1, emptydata[0]);
}
}
</script>
#Oleg - one more question on the solution you suggested. Sorry I tried myself to find it but couldn't.
In the buildSearchSelect: method , how can I include filter for empty string.
As explained above I have a "Add Row" button. So when the user wants to filter rows with empty columns I need a filter value.
The implementation of setSearchSelect function from my old answer work only if the searching toolbar not yet exist. If the toolbar exist one have to modify the options of the select element or autocomplete source of the jQuery UI autocomplete widget.
I extended the code. You can see the new version of the demo here. In the same way one could use inline editing instead of the cell editing.
Here is the modified JavaScript code:
var mydata = [
{id:"1", Name:"Miroslav Klose", Category:"sport", Subcategory:"football"},
{id:"2", Name:"Michael Schumacher", Category:"sport", Subcategory:"formula 1"},
{id:"3", Name:"Albert Einstein", Category:"science", Subcategory:"physics"},
{id:"4", Name:"Blaise Pascal", Category:"science", Subcategory:"mathematics"}
],
grid = $("#list"),
getUniqueNames = function(columnName) {
var texts = grid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
uniqueTexts.sort();
return uniqueTexts;
},
buildSearchSelect = function(uniqueNames) {
var values=":All";
$.each (uniqueNames, function() {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function(columnName) {
var $select = $('select#gs_'+columnName), un = getUniqueNames(columnName),
htmlForSelect = '<option value="">All</option>', i, l=un.length, val;
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value:buildSearchSelect(un),
sopt:['eq']
}
}
);
if ($select.length > 0) {
// The searching toolbar already exist. One have to update it manually
for (i=0;i<l;i++) {
val = un[i];
htmlForSelect += '<option value="'+val+'">'+val+'</option>';
}
$select.html(htmlForSelect);
}
},
setAutocomplete = function(columnName) {
var $input = $('input#gs_'+columnName), un = getUniqueNames(columnName);
grid.jqGrid('setColProp', columnName,
{
searchoptions: {
sopt:['cn'],
dataInit: function(elem) {
$(elem).autocomplete({
source:un,
delay:0,
minLength:0
});
}
}
});
if ($input.length > 0) {
// The searching toolbar already exist. One have to update the source
$input.autocomplete('option', 'source', un);
}
},
selectColumns = ['Category','Subcategory'], autocompleteColumns = ['Name'];
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name:'Name', index:'Name', width:200 ,editable:true},
{ name:'Category', index:'Category', width:200,editable:true },
{ name:'Subcategory', index:'Subcategory', width:200,editable:true }
],
sortname: 'Name',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
cellEdit: true,
cellsubmit: 'clientArray',
ignoreCase: true,
pager: '#pager',
height: "auto",
caption: "How to use filterToolbar better locally including local cell editing",
afterSaveCell: function(rowid,name,val,iRow,iCol) {
if ($.inArray(name,selectColumns) !== -1) {
setSearchSelect(name);
} else if ($.inArray(name,autocompleteColumns) !== -1) {
setAutocomplete(name);
}
}
}).jqGrid('navGrid','#pager',
{edit:false, add:false, del:false, search:false, refresh:true});
$.each(selectColumns,function() {
setSearchSelect(String(this));
});
$.each(autocompleteColumns,function() {
setAutocomplete(String(this));
});
grid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"cn"});
Related
I have a something like this:
i want to freeze the Doctor Name column which is Dynamic.
Actually, the whole grid is dynamic.
if (result[7] != null) {
var resu = JSON.parse(result[7]);
if (resu.length > 0) {
{
ColModel = [];
var model = Object.keys(resu[0]);
for (var i = 0; i < model.length; i++) {
var responColNM = "";
if (model[i] == "Doctor Name") {
responColNM = {
name: model[0], index: model[0], label: model[0], width: 140, editable: false, sortable: false, frozen: true,
}
}
else {
responColNM = {
name: model[i], index: model[i], label: model[i], width: 43, editable: false, sortable: false,
}
}
ColModel.push(responColNM);
}
}
}
strNew = resu;
}
else {
//store in arr
//str = { DOCTORNAME: '', CNT: '', DT: '' };
//strNew.push(str);
}
if (str == 1) {
colnames = [];
colmodel = ColModel;
$("#gvtable").jqGrid('setGridParam', { data: response }).trigger("reloadGrid");
$("#gvtable").jqGrid('setFrozenColumns').trigger("reloadGrid");
here, the column Doctor name does not freeze.
any suggestions?
Thanks in advance!
Some notes before to answer.
jqGrid name in colModel can't contain spaces. In your case it contain spaces
After call of setFrozenColumns method you do not need to trigger reloading the grid.
Finally, but not least, colModel can't be a dynamically changed. In order to do this you will need to destroy the grid and recreate it with the new colModel
The frozen column should be the first one in the array of colModel in order to be frozen. In your code it is not clear if it is first. You set the first column, but it is not known if it is first added in the colModel
I have a jqGrid custom function as editrules: { custom: true, custom_func: checkforduplicates, required:true }
However, I want this function to be run only in add mode, not in edit mode. Is this possible ?
EDIT:- After answer below from Oleg, I changed code to below. However, the alert does not print. Not sure where I am going wrong.
colModel: [
{ key: true, name: 'id', editable: false, formatter: 'integer', viewable: false, hidden: true },
{
key: false,
name: 'name',
editable: true,
editrules: {
required: true,
custom: function (options) {
// options have the following properties
// cmName
// cm
// iCol
// iRow
// rowid
// mode - "editForm", "addForm", "edit", "add", "cell" and so on
// newValue - the value which need be validated
// oldValue - the old value
// some additional properties depends on the editing mode
alert("mode is " + options.mode);
if (options.mode === "add") { // "add" for inline editing
var grid = $("#grid");
var textsLength = grid.jqGrid("getRowData");
var textsLength2 = JSON.stringify(textsLength);
alert("i am here");
var myAttrib = $.map(textsLength,
function (item) { return item.name });
var count = 0;
for (var k in textsLength) {
if (textsLength.hasOwnProperty(k)) {
++count;
}
}
var text, i;
for (i = 0; i < count; i++) {
text = myAttrib[i];
if (value === text) {
return [false, " - Duplicate category name."];
}
}
return [true, ""];
}
return true;
}
}
},
Free jqGrid supports old style custom_func with the options value, name and iCol and the new style validation. To use new style validation one don't need to specify any custom_func callback, but to define custom as the calback function with one parameter:
editrules: {
required: true,
custom: function (options) {
// options have the following properties
// cmName
// cm
// iCol
// iRow
// rowid
// mode - "editForm", "addForm", "edit", "add", "cell" and so on
// newValue - the value which need be validated
// oldValue - the old value
// some additional properties depends on the editing mode
if (options.mode === "addForm") { // "add" for inline editing
// do the validation
}
return true;
}
}
In case of validation of Add form the mode property is equal to "addForm", options.iRow === -1, options.oldValue === null, options.rowid === "_empty". It's recommended to use options.mode to detect the editing (or searching mode) in free jqGrid because the values of other properties (iRow, oldValue and rowid) depends on the editing mode.
For version 4.7 I use this method. Form for adding data class for the table. After that, special actions verified by the user are performed.
{
name : "LOGIN",
index : "LOGIN", editrules: {
required:true,
custom:true,
custom_func: dublicateUser
}
...
{
closeAfterAdd : true,
width : 500,
recreateForm : true,
afterShowForm : function () {
jQuery("#TblGrid_list_users").addClass('addMode');
}
...
function dublicateUser() {
var a;
var login = jQuery('#LOGIN').val();
var checkMode = jQuery('#TblGrid_list_users').hasClass('addMode');
jQuery.ajax({
type: 'POST',
data: {login:login, mode:checkMode},
url: 'code/validate_user.php',
async: false,
success: function(data) {
if (data == 'err') {
a = 1;
}
else {
a=0;
}
}
});
if (a==1) {
return[false,"error"];
}
else {
return[true];
}
}
I am able to get tree structure for the user stories but want it same for defects also which are related to particular user story so that at a singe screen I can see both user stories and the related defects.
You may use features: [{ftype:'groupingsummary'}] of ExtJS to group defects by user stories and even summarize by some other field, in the code below by PlanEstimate. To group defects by user story Requirement attribute on defect is used, which points to the related story. In this example defects are filtered by Iteration.
Ext.define('CustomApp', {
extend: 'Rally.app.TimeboxScopedApp',
componentCls: 'app',
scopeType: 'iteration',
comboboxConfig: {
fieldLabel: 'Select Iteration:',
labelWidth: 100
},
onScopeChange: function() {
this.makeStore();
},
makeStore: function() {
var filter = Ext.create('Rally.data.wsapi.Filter', {
property: 'Requirement',
operator: '!=',
value: null
});
filter= filter.and(this.getContext().getTimeboxScope().getQueryFilter());
filter.toString();
Ext.create('Rally.data.wsapi.Store', {
model: 'Defect',
fetch: ['ObjectID', 'FormattedID', 'Name', 'State', 'Requirement', 'PlanEstimate'],
autoLoad: true,
filters: [filter],
listeners: {
load: this.onDataLoaded,
scope: this
}
});
},
onDataLoaded: function(store, records){
if (records.length === 0) {
this.notifyNoDefects();
}
else{
if (this.notifier) {
this.notifier.destroy();
}
var that = this;
var promises = [];
_.each(records, function(defect) {
promises.push(this.getStory(defect, this));
},this);
Deft.Promise.all(promises).then({
success: function(results) {
that.defects = results;
that.makeGrid();
}
});
}
},
getStory: function(defect, scope) {
var deferred = Ext.create('Deft.Deferred');
var that = scope;
var storyOid = defect.get('Requirement').ObjectID;
Rally.data.ModelFactory.getModel({
type: 'HierarchicalRequirement',
scope: this,
success: function(model, operation) {
fetch: ['FormattedID','ScheduleState'],
model.load(storyOid, {
scope: this,
success: function(record, operation) {
var storyScheduleState = record.get('ScheduleState');
var storyFid = record.get('FormattedID');
var defectRef = defect.get('_ref');
var defectOid = defect.get('ObjectID');
var defectFid = defect.get('FormattedID');
var defectPlanEstimate = defect.get('PlanEstimate');
var defectName = defect.get('Name');
var defectState = defect.get('State');
var story = defect.get('Requirement');
result = {
"_ref" : defectRef,
"ObjectID" : defectOid,
"FormattedID" : defectFid,
"Name" : defectName,
"PlanEstimate" : defectPlanEstimate,
"State" : defectState,
"Requirement" : story,
"StoryState" : storyScheduleState,
"StoryID" : storyFid
};
deferred.resolve(result);
}
});
}
});
return deferred;
},
makeGrid: function() {
var that = this;
if (this.grid) {
this.grid.destroy();
}
var gridStore = Ext.create('Rally.data.custom.Store', {
data: that.defects,
groupField: 'StoryID',
pageSize: 1000,
});
this.grid = Ext.create('Rally.ui.grid.Grid', {
itemId: 'defectGrid',
store: gridStore,
features: [{ftype:'groupingsummary'}],
minHeight: 500,
columnCfgs: [
{
text: 'Formatted ID', dataIndex: 'FormattedID', xtype: 'templatecolumn',
tpl: Ext.create('Rally.ui.renderer.template.FormattedIDTemplate')
},
{
text: 'Name', dataIndex: 'Name',
},
{
text: 'State', dataIndex: 'State',
summaryRenderer: function() {
return "PlanEstimate Total";
}
},
{
text: 'PlanEstimate', dataIndex: 'PlanEstimate',
summaryType: 'sum'
},
{
text: 'Story', dataIndex: 'Story',
renderer: function(val, meta, record) {
return '' + record.get('Requirement').FormattedID + '';
}
},
{
text: 'Story Schedule State', dataIndex: 'StoryState',
}
]
});
this.add(this.grid);
this.grid.reconfigure(gridStore);
},
notifyNoDefects: function() {
if (this.grid) {
this.grid.destroy();
}
if (this.notifier) {
this.notifier.destroy();
}
this.notifier = Ext.create('Ext.Container',{
xtype: 'container',
itemId: 'notifyContainer',
html: "No Defects found matching selection."
});
this.add( this.notifier);
}
});
I have a project where I want to inline edit a value in a table generated via DataTables and am therefore using dataTables.editable
The table is rendering fine but when I try and to sumit an edit I get an error and if I look at the return value the id field is blank.
The controller action is as follows:
public ActionResult AjaxHandler(jQueryDataTableParamModel param)
{
var allMonthlyCosts = _unitOfWork.MonthlyCostRepository.Get(includeProperties: "Period, Employee");
IEnumerable<MonthlyCost> filteredMonthlyCosts;
if (!string.IsNullOrEmpty(param.sSearch))
{
filteredMonthlyCosts = _unitOfWork.MonthlyCostRepository.Get(includeProperties: "Period, Employee")
.Where(mc => mc.Period.Name.Contains(param.sSearch)
||
mc.Employee.ClockNo.Contains(param.sSearch));
}
else
{
filteredMonthlyCosts = allMonthlyCosts;
}
var displayedMonthlyCosts = filteredMonthlyCosts
.Skip(param.iDisplayStart)
.Take(param.iDisplayLength);
var result = from mc in displayedMonthlyCosts
select new { ID = mc.Id, EvisionCost = mc.EvisionCost, EmployeeNo = mc.Employee.ClockNo, PeriodName = mc.Period.Name, TotalDays = mc.TotalDays, TotalCost = mc.TotalCost() };
return Json(new
{
sEcho = param.sEcho,
iTotalRecords = allMonthlyCosts.Count(),
iTotalDisplayRecords = filteredMonthlyCosts.Count(),
aaData = result
},
JsonRequestBehavior.AllowGet);
}
The Javascript is as follows:
$('#myDataTable').dataTable({
"bServerSide": true,
"sAjaxSource": "MonthlyCost/AjaxHandler",
"bProcessing": true,
"aoColumns": [
{ "mData": "ID",
"bSearchable": false,
"bSortable": false,
"bVisible": false
},
{ "mData": "EvisionCost" },
{ "mData": "PeriodName" },
{ "mData": "EmployeeNo" },
{ "mData": "TotalDays" },
{ "mData": "TotalCost" }
]
}).makeEditable({
sUpdateURL: "/MonthlyCost/UpdateData",
"aoColumns": [
{},
null,
null,
null,
null]
});
The error I get is:
Cell cannot be #Updated(Server Error)
And the returned form is as follows:
value:2505
id:
rowId:0
columnPosition:0
columnId:1
columnName:EvisionCost
Issue is quite st.forward
Your editing is not reaching this plug-in code below . Thats why its throwing the error of your mention
CODE IN EDITABLE DATATABLE PLUGIN:
//Utility function used to apply editable plugin on table cells
function fnApplyEditable(aoNodes) {
var oDefaultEditableSettings = {
event: 'dblclick',
"callback": function (sValue, settings) {
properties.fnEndProcessingMode();
if (sNewCellValue == sValue) {
var aPos = oTable.fnGetPosition(this);
oTable.fnUpdate(sValue, aPos[0], aPos[2]);
} else {
var aPos = oTable.fnGetPosition(this);
oTable.fnUpdate(sOldValue, aPos[0], aPos[2]);
properties.fnShowError(sValue, "update");
}
},
"submitdata": function (value, settings) {
properties.fnStartProcessingMode();
sOldValue = value;
sNewCellValue = $("input,select", $(this)).val();
var id = fnGetCellID(this);
var rowId = oTable.fnGetPosition(this)[0];
var columnPosition = oTable.fnGetPosition(this)[1];
var columnId = oTable.fnGetPosition(this)[2];
var sColumnName = oTable.fnSettings().aoColumns[columnId].sName;
if (sColumnName == null || sColumnName == "")
sColumnName = oTable.fnSettings().aoColumns[columnId].sTitle;
return {
"id": id,
"rowId": rowId,
"columnPosition": columnPosition,
"columnId": columnId,
"columnName": sColumnName
};
},
"onerror": function () {
properties.fnEndProcessingMode();
properties.fnShowError("Cell cannot be updated(Server error)", "update");
},
"height": properties.height
};
This issue i am facing recently and i am trying like
<script type="text/javascript">
$(document).ready(function () {
$('#myDataTable').dataTable({ "bProcessing": true,
**"bServerSide": true,
"sAjaxSource": 'Home/AjaxHandler',
"sUpdateURL": '#Url.Action("UpdateData","Home")',
"sAddURL": '#Url.Action("AddData","Home")' ,
"sDeleteURL": '#Url.Action("DeleteData","Home")',**
"aoColumns": [
{ "sName": "ID",
"bSearchable": false,
"bSortable": false,
"bVisible": false
},
{ "sName": "Contact_Name" },
{ "sName": "Contact_Address" },
{ "sName": "Lead_Source" },
{ "sName": "Domain" },
]
}).makeEditable();
});
</script>
}
If this work please let me know . If you find any other way around do mention it . I am also in the same situation like you Finding answers
Regards
Can someone help me with this issue?
I have a jqgrid(4.4.0) and I want to implement true scrolling. The problem is that it only loads datarows once, meaning the first page only. So when I scroll, it doesn't fetch the other pages. I have checked this issue and still not working.
Here is the jqgrid:
jQuery("#deptProjectsGrid").jqGrid({
url: '#Url.Action("GetUserProjects", "TimesheetByWeek")',
datatype: 'json',
mtype: 'GET',
colNames: ['Projekt', 'Oprettet af'],
colModel: [
{ name: 'project', index: 'project', sortable: true, align: 'left' },
{ name: 'creator', index: 'creator', align: 'left' }
],
height: 300,
width: 250,
altRows: true,
pager: '#pager1',
scroll: 1,
rowNum: 15,
rownumbers: true,
viewrecords: true,
sortname: 'project',
sortorder: 'desc',
gridview: true,
caption: "Projekter",
onSelectRow: function (ids) {
if (ids == null) {
ids = 0;
if ($taskgrid.jqGrid('getGridParam', 'records') > 0) {
$taskgrid.jqGrid('setGridParam', { url: '#Url.Action("GetProjectTasks", "TimesheetByWeek")/' + ids });
$taskgrid.jqGrid('setCaption', "No Tasks " + ids).trigger('reloadGrid');
}
} else {
var data = $("#deptProjectsGrid").getRowData(ids);
$taskgrid.jqGrid('setGridParam', { url: '#Url.Action("GetProjectTasks", "TimesheetByWeek")/' + ids });
$taskgrid.jqGrid('setCaption', "Tasks for " + data.project).trigger('reloadGrid');
}
}
});
The controller action looks like this:
public JsonResult GetUserProjects(int page, int rows, string search, string sidx, string sord)
{
try
{
using (DanishEntities db = new DanishEntities())
{
int totalRecords = 0;
var allProjectEntities = _projectRepository.GetProjectsPaged(page, rows, out totalRecords, db);
var projects = Mapper.Map<List<Project>, List<ProjectModel>>(allProjectEntities);
var totalPages = (int)Math.Ceiling(totalRecords / (float)rows);
var jsonData = new
{
total = rows,
page = page++,
records = totalRecords,
rows = (
from p in projects
select new
{
id = p.ID,
cell = new object[] { p.Name, "john doe" }
}).ToArray()
};
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
}
catch (Exception)
{
throw;
}
}
and the query is:
public List<Project> GetProjectsPaged(int page, int rows, out int totalCount, DanishEntities dbContext)
{
List<Project> pagedProjectEntities = new List<Project>();
try
{
totalCount = dbContext.Projects.Count();
pagedProjectEntities = dbContext.Projects
.OrderBy(p => p.ID)
.Skip((page-1) * rows)
.Take(rows)
.ToList();
}
catch (Exception)
{
throw;
}
return pagedProjectEntities;
}
I have wasted 4 hours of my life trying to figure this out and I just can't see the problem. I have even set "total = totalPages" in the controller action but nothing is working. Help please!!
Just another quick question on jqGrid: How do I disable "rowNum" in a jqGrid so that the grid shows all available rows returned by the query in the data set?