I'm loading a jqGrid on my page. The grid has a Delete button for each row. I'm trying to use the jquery UI dialog confirmation on my Delete button.
Here's my javascript code:
<script type="text/javascript">
$(document).ready(function () {
$("#list").jqGrid({
url: '/MyController/MyFunction/',
datatype: 'json',
mtype: 'POST',
colNames: ['', 'Name', ''],
colModel: [
{ name: 'Edit', index: 'Edit', width: 40, align: 'left', sortable: false },
{ name: 'Name', index: 'Name', width: 120, align: 'left' },
{ name: 'Delete', index: 'Delete', width: 50, align: 'left', sortable: false }],
pager: $('#pager'),
rowNum: 10,
rowList: [10, 20, 50],
sortname: 'Name',
sortorder: "asc",
viewrecords: true,
width: 700
});
$("#dialog-confirm").dialog({
autoOpen: false,
modal: true,
buttons: {
"Delete": function () {
window.location.href = $(this).attr("href"); ;
},
Cancel: function () {
$(this).dialog("close");
}
}
});
$("a.confirm").click(function () {
alert("HELLO");
//$("#dialog-confirm").dialog("open");
});
});
</script>
I'm passing in data from my controller to the grid. I have the class "confirm" added to the Delete link for each row.
If I click on my Delete button, nothing happens. The link has the correct class, and all my javascript is loading correctly. I placed an alert at the end of my document.ready function to make sure there were no errors.
But if I comment out my jqGrid and add a link onto my page with the class "confirm", the click event will fire.
Has anyone ever run into this?
The main problem which you have is that you try to make 'click' binding with $("a.confirm").click(...) before the elements "a.confirm" are loaded.
You should either place the binding code inside of loadComplete or gridComplete event handler or use jQuery.live
$("a.confirm").live('click', function() {
alert("HELLO");
//$("#dialog-confirm").dialog("open");
});
instead of $("a.confirm").click(...).
One more general remark. The best practice working with jqGrid is dividing data from the HTML markup. I suppose that you place HTML fragment with <a class="confirm">...</a> inside of JSON data returned from the server. jqGrid supports another ways to archive the same results. You can 1) use showlink formatter; 2) use custom formatter which allow create any HTML fragment for the grid cell based on the row of data (see rowObject parameter) returned from the server 3) use unobtrusive JavaScript (see my answer with the code example) 4) any mix from both (see another answer with the code example). The way 3 seems me mostly close to what you do.
In any way having clear separation of JSON data from HTML markup is good not only because of design reason. It allows additionally reduce the size of data send from server. (see this answer for more information)
Related
Consider I am showing toppers of each subject from a DB using Jtable.I have integrated this with Spring MVC.
$('#TableContainer').jtable({
//title: 'Members',
selectOnRowClick:true,
selecting: true, //Enable selecting
paging: true, //Enable paging
pageSize: 10, //Set page size (default: 10)
sorting: false, //Enable sorting
actions: {
listAction: myurl+'LoadMarks?subject='+subject,
},
fields: {
ExamDate: {
title: 'Exam Date',
},
StudentID: {
title: 'Student',
},
Marks: {
title: 'Marks Awarded',
}
}
});
At page load I am using $('#TableContainer').jtable('load');
Now I need to make this dynamic by providing user a dropdown and on change of dropdown I need to reload jQuery jTable with respective columns.
If using $('#TableContainer').jtable('reload'); the url is getting called but I need to change ListAction variable (URL) and reload the page.
I need to change url and load/reload jTable
Thanks In advance :)
Finally Found the Answer
I needed to destroy the Jtable.
But,$('#TableContainer').jtable('destroy'); does not work you can do it by.
refer link
$('#TableContainer').jtable({
});
$('#TableContainer').jtable('destroy');
then you need load JTable
I have the following setup for jQgrid 5.1.0:
<div id="grid_container">
<table id="grid"></table>
<div id="gridpager"></div>
</div>
<script type="text/javascript">
$.fn.fmatter.btnFormatter = function (cellValue, options, rowData, addOrEdit) {
var btn =
'<a href="#">' +
'<img class="api_button" data-id="' + options.rowId + '" src="/images/icons/16x16/view.png" alt="Show API Response data" title="Show API Response data" />' +
'</a>' +
'<a href="#">' +
'<img class="error_button" data-id="' + options.rowId + '" src="/images/icons/16x16/view.png" alt="Show errors" title="Show errors" />' +
'</a>';
return btn;
};
$(function () {
$("#grid").jqGrid({
url: '/sf/api-logs',
datatype: "json",
colNames: {{ colNames|raw }},
colModel: {{ colFormats|raw }},
width: 980,
height: 300,
pager: "#gridpager",
toppager: true,
hoverrows: true,
shrinkToFit: true,
autowidth: true,
rownumbers: true,
viewrecords: true,
rowList: [10, 20, 50, 100],
data: [],
rownumWidth: 50,
sortable: true,
jsonReader: {
root: 'rows',
page: 'page',
total: 'total',
records: 'records',
cell: '',
repeatitems: false
},
loadComplete: function (data) {
if (data.records === 0) {
$("#load_grid").addClass("info_msg").html($("<span>", {
"class": "grid-empty",
"text": "No results were found."
})).delay(800).fadeIn(400);
}
}
}).on('click', '.api_button', function () {
var apiResponseContent = $('#apiResponseContent');
$.ajax({
type: "GET",
url: '/sf/api-logs/api-response',
data: {id: $(this).data('id')},
dataType: 'json',
success: function (data) {
if (typeof data[0].error !== 'undefined') {
apiResponseContent.text(data[0].error);
}
apiResponseContent.text(data[0].apiResponse);
$('#api_dialog').dialog('open');
}
});
return false;
});
$('#api_dialog').dialog({
autoOpen: false,
width: 600,
height: $(window).height() * 0.9,
modal: true,
buttons: {
Ok: function () {
$(this).dialog('close');
}
}
}).show();
});
</script>
But as the image below shown the pagination is not working and the small icon for refresh the grid is not being displayed either, what I am doing wrong here?
UPDATE
I have managed to show the refresh button by adding the following code:
$('#grid').jqGrid('navGrid', '#gridpager', {
edit: false,
add: false,
del: false,
search: false,
refresh: true,
refreshstate: "current"
})
But it only appears on the #gridpagger what about if I want it also on the top bar?
Here is an example of the data returned by the server: https://gist.github.com/reypm/b1d2a303ba471261e55d72bbef099b74
You reported about two problems: pagination not working and the Refresh button appears on the bottom pager only (not on the top-pager).
The problem with Refresh button seems be mostly simple. You use commercial Guriddo, which probably still have the same logic of working with pagers like jqGrid 4.7. Old jqGrid has two pager options: pager and toppager, which values have to be specified in different ways. Working with toppager is easy: one can add toppager: true option and jqGrid will generate the top-pager div itself and to replace the value of toppager from true to the id selector of new pager. It will be toppager: "#grid_toppager". On the other side, to create the pager on the bottom of the grid one have to create somewhere on the HTML page dummy div, like <div id="gridpager"></div> and to use pager parameter in the form pager: "gridpager". jqGrid will move the div on another place inside of the grid and to fill it with data. Other methods like navGrid, inlineNav, navButtonAdd have to use #gridpager or "#grid_toppager" as parameter to create the navigator bar and to add buttons to the bar. Thus you have to use the code like
$('#grid').jqGrid('navGrid', '#grid_toppager', {
edit: false,
add: false,
del: false,
search: false,
refreshstate: "current"
});
or
var $grid = $('#grid'),
topPagerSelector = $grid.jqGrid('getGridParam', 'toppager');
$grid.jqGrid('navGrid', topPagerSelector, {
edit: false,
add: false,
del: false,
search: false,
refreshstate: "current"
});
to create the navigator bar on the top-pager and to add the Refresh button to it. Alternatively you can use cloneToTop: true option of navGrid to add the same pagers to both pagers:
$('#grid').jqGrid('navGrid', '#gridpager', {
cloneToTop: true,
edit: false,
add: false,
del: false,
search: false,
refreshstate: "current"
});
You can't use the option if you want to have only one top pager. You will have to use '#grid_toppager' with navButtonAdd method.
I develop free jqGrid fork of jqGrid. I simplified the behavior already in the first version of free jqGrid published in the 2015: see the wiki article. One can use pager: true in the same way like toppager: true and one can skip pager parameter in navGrid, inlineNav, navButtonAdd. The usage of navGrid could be
$('#grid').jqGrid('navGrid', {
edit: false,
add: false,
del: false,
search: false,
refreshstate: "current"
});
to add the navigator buttons on all pagers of the grid (top, bottom or both).
It's only one small difference between free jqGrid and Guriddo jqGrid. There are hundreds of other changes. I recommend you to consider to migrate to free jqGrid even if you payed Guriddo jqGrid license. I'd recommend you to read the page with the base information about the usage of free jqGrid.
The paging of data don't work because the response from your server is wrong. It looks like
{
"page": 1,
"total": 0,
"records": 67,
"rows": [
{ "id": "590a363477336501ad44ab02", "dataObject": "Account", ...},
...
{ "id": "590c97197ad70f00575a310a", "dataObject": "AgreementHistory", ...}
]
}
You use datatype: "json" option without loadonce: true option, which corresponds server side paging. It means that jqGrid send to url requests with rows and page parameter. The first request, which send jqGrid will contains page=1&rows=20 (20 is the default value of rowNum parameter of jqGrid) and the server have to return 20 or less rows (return only one requested page of data). Additional total and records property informs jqGrid about the total number or pages and records. Based on the value of total parameter jqGrid will disable pager buttons and the user will be not able to make paging correctly.
One the other side, your server response contains wrong value of total property and all 67 rows instead of 20 requested rows. Other 47 rows of the serve response will be just ignored by jqGrid.
If you have scenario, where the total number of records is not large (like 67 in you case), then it's recommended to add loadonce: true option (and forceClientSorting: true additionally in case of usage free jqGrid) and to modify the server response to
[
{ "id": "590a363477336501ad44ab02", "dataObject": "Account", ...},
...
{ "id": "590c97197ad70f00575a310a", "dataObject": "AgreementHistory", ...}
]
with all rows of the grid. jqGrid will fill internal data parameter, it will change datatype to "local" automatically after the first loading the data. As the result paging, sorting and filtering/searching (try filterToolbar or search: true of navGrid) locally without any additional communication to the server. It essentially simplify the server code and improves the performance of jqGrid. Even relatively large number of rows can be processed very quickly if you use small enough page size (like rowNum: 20 or rowNum: 10). You can try the demo with 60000 rows, 15 columns and 25 rows per page. You can test the time of paging, sorting and filtering.
I'm using jqGrid and have setup an action handler where I want the user to be able to delete a row. The callback specified in the URL is being called, but I can't figure out how to pass the row ID to the URL handler so I know which row to delete.
Anyone have a solution to this?
<script>
$( document ).ready(function() {
$("#list2").jqGrid({
url:'datahandler',
datatype: "json",
colNames:['Name','Description', 'Data (Abbreviated)', 'Actions'],
colModel:[
{name:'name',index:'name', width:300, resizeable:true},
{name:'description',index:'description', width:300, resizeable:true},
{name:'data',index:'data', width:600, resizeable:true},
{name : 'actions', sortable:false, index: 'actions', formatter:'actions',
formatoptions: {
keys: true,
editbutton: false,
delOptions: { url: 'deleterow' }
}}
],
rowNum:10,
rowList:[10,20,30],
pager: '#pager2',
sortname: 'name',
viewrecords: true,
sortorder: "desc",
caption:"PVSyst Data",
});
$("#list2").jqGrid('navGrid','#pager2',{edit:false,add:false,del:false});
});
</script>
It's not clear which format exactly you use to fill the grid and which rowid you use. Typical error exist if the data wrong filled and the values 1, 2, 3 will be used instead of rowids which you want to see on the server side. In any way the above code will use HTTP POST request to the URL "deleterow" specified in delOptions. The data have the format described in the documentation of delGridRow (see here). For example if the id of deleted row is "123" then the data posted to the URL "deleterow" will be
oper=del&id=123
You need just implement reading of the id parameter on the server side. If you want to rename the name of parameter from id to any other text like myId then you can use jqGrid option prmNames: { id: "myId" }. After that the posted data will look like
oper=del&myId=123
I need to load a JSON from server and i want to enable a user to click and edit the value.
But when they edit, it should not call server. i mean i am not going to update immediately. So i dont want editurl. So i tried
'ClientArray' But still it shows Url is not set alert box. But i need
all the edited values when the user click Add Commented Items button this button will fire AddSelectedItemsToSummary() to save those in server
MVC HTML Script
<div>
<table id="persons-summary-grid"></table>
<input type="hidden" id="hdn-deptsk" value="2"/>
<button id="AddSelectedItems" onclick="AddSelectedItemsToSummary();" />
</div>
$(document).ready(function(){
showSummaryGrid(); //When the page loads it loads the persons for Dept
});
JSON Data
{"total":2,"page":1,"records":2,
"rows":[{"PersonSK":1,"Type":"Contract","Attribute":"Organization
Activity","Comment":"Good and helping og"},
{"PersonSK":2,"Type":"Permanant","Attribute":"Team Management",
"Comment":"Need to improve leadership skill"}
]}
jQGRID code
var localSummaryArray;
function showSummaryGrid(){
var summaryGrid = $("#persons-summary-grid");
// doing this because it is not firing second time using .trigger('reloadGrid')
summaryGrid.jqGrid('GridUnload');
var deptSk = $('#hdn-deptsk').val();
summaryGrid.jqGrid({
url: '/dept/GetPersonSummary',
datatype: "json",
mtype: "POST",
postData: { deptSK: deptSk },
colNames: [
'SK', 'Type', 'Field Name', 'Comments'],
colModel: [
{ name: 'PersonSK', index: 'PersonSK', hidden: true },
{ name: 'Type', index: 'Type', width: 100 },
{ name: 'Attribute', index: 'Attribute', width: 150 },
{ name: 'Comment', index: 'Comment', editable: true,
edittype: 'textarea', width: 200 }
],
cellEdit: true,
cellsubmit: 'clientArray',
editurl: 'clientArray',
rowNum: 1000,
rowList: [],
pgbuttons: false,
pgtext: null,
viewrecords: false,
emptyrecords: "No records to view",
gridview: true,
caption: 'dept person Summary',
height: '250',
jsonReader: {
repeatitems: false
},
loadComplete: function (data) {
localSummaryArray= data;
summaryGrid.setGridParam({ datatype: 'local' });
summaryGrid.setGridParam({ data: localSummaryArray});
}
});
)
Button click function
function AddSelectedItemsToSummary() {
//get all the items that has comments
//entered using cell edit and save only those.
// I need to prepare the array of items and send it to MVC controller method
// Also need to reload summary grid
}
Could any one help on this? why i am getting that URL is not set error?
EDIT:
This code is working after loadComplete changes. Before it was showing
No URL Set alert
I don't understand the problem with cell editing which you describe. Moreover you wrote "i need the edited value when the user click + icon in a row". Where is the "+" icon? Do you mean "trash.gif" icon? If you want to use cell editing, how you imagine it in case of clicking on the icon on the row? Which cell should start be editing on clicking "trash.gif" icon? You can start editing some other cell as the cell with "trash.gif" icon ising editCell method, but I don't think that it would be comfortable for the user because for the users point of view he will start editing of one cell on clicking of another cell. It seems me uncomfortable. Probably you want implement inline editing?
One clear error in your code is usage of showSummaryGrid inside of RemoveFromSummary. The function RemoveFromSummary create jqGrid and not just fill it. So one should call it only once. To refresh the body of the grid you should call $("#persons-summary-grid").trigger("refreshGrid"); instead. Instead of usage postData: { deptSK: deptSk } you should use
postData: { deptSK: function () { return $('#hdn-deptsk').val(); } }
In the case triggering of refreshGrid would be enough and it will send to the server the current value from the '#hdn-deptsk'. See the answer for more information.
UPDATED: I couldn't reproduce the problem which you described, but I prepared the demo which do what you need (if I understand your requirements correctly). The most important part of the code which you probably need you will find below
$("#AddSelectedItems").click(function () {
var savedRow = summaryGrid.jqGrid("getGridParam", "savedRow"),
$editedRows,
modifications = [];
if (savedRow && savedRow.length > 0) {
// save currently editing row if any exist
summaryGrid.jqGrid("saveCell", savedRow[0].id, savedRow[0].ic);
}
// now we find all rows where cells are edited
summaryGrid.find("tr.jqgrow:has(td.dirty-cell)").each(function () {
var id = this.id;
modifications.push({
PersonSK: id,
Comment: $(summaryGrid[0].rows[id].cells[2]).text() // 2 - column name of the column "Comment"
});
});
// here you can send modifications per ajax to the server and call
// reloadGrid inside of success callback of the ajax call
// we simulate it by usage alert
alert(JSON.stringify(modifications));
summaryGrid.jqGrid("setGridParam", {datatype: "json"}).trigger("reloadGrid");
});
The custom_value of place_id is set to whichever row I click first. Subsequent clicked rows will all use that same value, regardless of their actual value. Why?
example:
place_id foo_name bar_value
10 blah abc
11 blah2 fgr
click the row with the place_id of 10 and click "edit" and the form that appears will have 10 for the place_id value. Make a change and save it then click the next row down. The form will still have the place_id of 10 though all other values will be correct.
My code:
The column place_id looks like this:
{name:'place_id', index:'place_id', editable: true, edittype:'custom',
editoptions: { custom_element:myelem,custom_value:myval }}
The myval function is:
function myval(elem){
return elem.val();
}
What I need is for the myval to be set to the correct place_id for the row being edited. I looked at the elem object in Firebug and I see that it always has the value of whichever row was first clicked but I don't understand why nor do I see where I can grab the correct value from. Any suggestions are appreciated (I tried asking on the jqgrid forums but nothing came of it so I'm turning to stackoverflow).
*Edit: If I use edittype:'text' rather than edittype:'custom' I get the correct values displayed and passed but then the column is editable and it should only be visible but not editable.
Full code:
jQuery(document).ready(function(){
jQuery("#list").jqGrid({
url:'/foo/bar/results',
datatype: 'json',
mtype: 'POST',
colNames:['Place ID', 'Site ID', 'Site Name', 'API ID', 'M Type'],
colModel :[
{name:'place_id', index:'place_id', key: true, sorttype:'integer',
width:70, editable: true, edittype:'custom',
editoptions: {custom_element:myelem,custom_value:myval }},
{name:'site_id', index:'site_id', sorttype:'integer', width:70,
editable: true, edittype: 'select', editrule: {required: true},
editoptions:{value:getSites(), size:30}},
{name:'site_name', index:'site_name', width:150, editable: false,
editrule: {required: true}, editoptions: {size:30}},
{name:'api_id', index:'api_id', sorttype:'integer', width:75,
editable: true, edittype: 'text', editrules: {required: true},
editoptions:{size:30}},
{name:'m_type', index:'m_type', width:150, editable: true,
edittype: 'select', editrules: {required: true},
editoptions:{value:{'one':'one','two':'two','three':'three',
'four':'four'},size:30}}
],
editurl:'/foo/bar/editinfo',
height: 'auto',
width: 'auto',
pager: '#pager',
viewrecords: true,
loadonce: true,
rowNum:20,
rowList:[20,40,60,80,100],
caption: 'Meter Listing'
});
// Edit functionality
$("#editfields").click(function(){
var gr = jQuery("#list").jqGrid('getGridParam','selrow');
if( gr != null ) {
jQuery('#list').setGridParam({datatype:'json'});
jQuery("#list").jqGrid('editGridRow',gr,
{editCaption: 'Edit Place Details',height:550,
closeAfterEdit:true,width:600,reloadAfterSubmit:true});
} else {
alert("Please select a row");
}
});
});
function myelem(value,options){
return $('<input type="text" value="'+value+'" disabled="disabled"/>');
}
function myval(elem){
return elem.val();
}
edit2:
getSites:
function getSites(){
<?php
$sites = "0:Select";
foreach ($this->sites as $k => $v){
$sites = $sites . ";" . $v['site_id'] . ":" . $v['site_name'];
}
?>
return "<?= $sites ?>";
}
Could you try to include key: true in the definition of the place_id column. You can remove id from the data which you send from the server.
If it will not help, then you should post a full code example which reproduce your problem and I will try to find a workaround.
UPDATED: Sometime there are a simple solution for complex problems. One additional parameter of editGridRow function solve your problem:
recreateForm: true
Without using of the parameter the function myelem will be called only one time at the first edit of the selected row. Then the form will be cached and not recreated. So you will be edit always the same row. After including of the parameter recreateForm: true the form will be created every time.
By the way I set some general settings which I use in all jqGrids per extending jQuery.jgrid.defaults, jQuery.jgrid.edit, jQuery.jgrid.view, jQuery.jgrid.del and jQuery.jgrid.nav. For example I use always
jQuery.extend(jQuery.jgrid.edit, {
closeAfterAdd: true,
closeAfterEdit: true,
recreateForm: true,
//...
});
Then I don't need set this parameters later. During writing of the answer Add multiple input elements in a custom edit type field about custom editing I has also the settings, so I didn't see any problems.