I have a JQGrid.I need to take some Id to the OnClick function.In my scenario i wanted to get BasicId to the OnClick function.
MyCode
function grid() {
//JqGrid
$('#griddata').html('<table class="table" id="jqgrid"></table>')
$('#jqgrid').jqGrid({
url: '/Admin/GetBasicData/',
datatype: 'json',
mtype: 'GET',
//columns names
colNames: ['BasicId','Images'],
//columns model
colModel: [
{ name: 'BasicId', index: 'BasicId', resizable: false },
{
name: 'Images',
width: 120,
formatter: function () {
return "<button class='btn btn-warning btn-xs' onclick='OpenDialog()' style='margin-left:30%'>View</button>";
}
},
//Some Code here
Open Dialog Function
function OpenDialog(BasicId)
{
//Some code here
}
You can use onclick='OpenDialog.call(this, event)' instead of onclick='OpenDialog()'. You will have this inside of OpenDialog initialized to the clicked <button> and the event.target. Thus your code could be like the following
function OpenDialog (e) {
var rowid = $(this).closest("tr.jqgrow").attr("id"),
$grid = $(this).closest(".ui-jqgrid-btable"),
basicId = $grid.jqGrid("getCell", rowid, "BasicId");
// ...
e.stopPropagation();
}
One more option is even better: you don't need to specify any onclick. Instead of that you can use beforeSelectRow callback of jqGrid:
beforeSelectRow (rowid, e) {
var $td = $(e.target).closest("td"),
iCol = $.jgrid.getCellIndex($td[0]),
colModel = $(this).jqGrid("getGridParam", "colModel"),
basicId = $(this).jqGrid("getCell", rowid, "BasicId");
if (colModel[iCol].name === "Images") { // click in the column "Images"
// one can make additional test for
// if (e.target.nodeName.toUpperCase() === "button")
// to be sure that it was click to the button
// and not the click on another part of the column
OpenDialog(rowid);
return false; // don't select the row - optional
}
}
The main advantages of the last approach: one don't need to make any additional binding (every binding get memory resources and it take time). There are already exist on click handler in the grid and one can use it. It's enough to have one click handler because of event bubbling. The e.target provide us still full information about the clicked element.
Writing js event in your buttons html is not a good idea, its against 'un-obtrusive javasript' principle. You can instead add a click event on the entire grid in the render function and in the callback, filter out based on whether the button was clicked.
//not sure of the syntax of jqgrid, but roughly:
render: function(){
$('#jqgrid').unbind('click').on('click', function(){
if($(e.target).hasClass('btn-warning')){
var tr = $(e.target).parent('tr');
//retrieve the basicId from 'tr'
OpenDialog(/*pass the basicId*/)
}
})
}
Related
I want to add the search keyword to the URL of a custom button action element in order to pass the keyword as a GET parameter.
I am initializing the data table like so:
var table = $('#list').DataTable( {
dom: 'lBfrtip',
buttons: [
{
text: 'Export to PDF',
className: 'export-to-pdf',
action: function ( e, dt, button, config ) {
window.open('generate_pdf.php?case_id=<?= $case_id? ?>','_blank');
}
And attempting to append the keyword to the URL using:
// append keyword search values to pdf url
$('#list').on('search.dt', function() {
var keyword = $('.dataTables_filter input').val();
//FAILS HERE
var export_pdf_url = $(".export-to-pdf").attr("href");
// remove keywords if they already exist
removeURLParameter(export_pdf_url, 'keyword');
// append filter value to filtered pdf href
$(".export-to-pdf").attr("href", export_pdf_url + '&keyword='+keyword);
});
This seems to be failing because the action function is not actually assigning the the button a href attribute.
Any suggestions on how to dynamically modify the action function or other approaches would be very much appreciated.
Use search() API method which returns currently applied global search when called without arguments.
Then generate URL directly in the callback function for action option.
For example:
buttons: [
{
text: 'Export to PDF',
className: 'export-to-pdf',
action: function ( e, dt, button, config ) {
var query = dt.search();
window.open('generate_pdf.php?case_id=<?= $case_id? ?>&keyword=' + encodeURIComponent(query), '_blank');
}
}
],
I just implemented a DataTable in my app, but it seems like javascript doesn't work within the DataTable.
I've attached all code below for better readability.
As you can see, the ccbtn_action="delete" bit is present, but Chrome/IE/FF doesn't seem to want to do anything when the glyphicon is clicked.
This code works perfectly when called from outside the DataTable.
What gives? Is it something to do about JavaScript not being applied to dynamically generated elements?
Thank you!
Here is the Javascript code that doesn't work:
$(document).ready(function(){
// Delete Records
$('[ccbtn_action="delete"]').on('click', function() {
var type = $(this).attr('ccbtn_value_type');
var value = $(this).attr('ccbtn_value_id');
console.log('type=' + type + '&id=' + value);
if (confirm('Are you sure you want to PERMANENTLY delete this record? There is NO TURNING BACK!')) {
$.ajax({
type: 'POST',
url: 'includes/crmcore_action.php?action=cc_delete',
data: 'type=' + type + '&id=' + value,
success:
function() {
$('#cc_pagetop_status').html("<div class='alert alert-success'><strong>Success!</strong> The record was successfully deleted.</div>");
if (type == "company")
{
window.location = "companies_list.php";
}
else
{
location.reload();
}
}
});
} else {
// Do nothing!
}
});
});
Here is the code for the DataTable:
$(document).ready(function() {
var t = $('#DataTable').DataTable({
"order": [[ 1, 'asc' ]],
ajax: {
url: 'includes/dt_ss.php?getwhat=company',
dataSrc: ''
},
columns: [
{data: null},
{"data": null,
"render": function (data, type, row)
{
return ''+data.name+'';
}
},
//{data: 'name'},
{data: 'tel'},
{
"data": "id",
"render": function ( data, type, full, meta )
{
return '<span class="glyphicon glyphicon-remove" ccbtn_action="delete" ccbtn_value_type="company" ccbtn_value_id="'+data+'" data-toggle="tooltip" data-placement="bottom" title="Click me to delete"></span>';
}
}
],
});
t.on( 'order.dt search.dt', function () {
t.column(0, {search:'applied', order:'applied'}).nodes().each( function (cell, i) {
cell.innerHTML = i+1;
} );
} ).draw();
});
Since the js looks ok, this is most probably a timing issue. You part of script that binds the events is executed before the actual elements are created.
To fix that, you can:
Make sure the script runs binding after elements creation
Use dynamic binding (like .delegate() http://api.jquery.com/delegate/)
Try delegating your event like this:
$('#DataTable').on('click', '[ccbtn_action="delete"]', function() { ...
My guess is the click event is attached before your ajax request loads the DataTable rows. You can read more here about jQuery event delegation with on(). Specifically:
Event handlers are bound only to the currently selected elements; they must exist at the time your code makes the call to .on()
Try like this, but jquery version must be 1.9+
$(document).on('click', '[ccbtn_action="delete"]', function() { // your remaining code
In my jqGrid, I have a checkbox which is also available for editing, i.e. a user can click on the checkbox and that checkbox's value will be updated in the database. That is working fine. However when I click on the checkbox and if I try clicking on it again, nothing happens. The row does not get saved. Theoretically the unchecked value of the checkbox should be saved. But this does not happen.
I have tried referring to this answer of Oleg but it does not help.
The weird problem is if I select another row and then try to unselect the checkbox again, I do see a save request going.
I am guessing this is because I am trying to edit a row which is currently selected. But I am not sure what I am doing wrong here.
This is what I am doing in my beforeSelectRow
beforeSelectRow: function (rowid, e) {
var $target = $(e.target),
$td = $target.closest("td"),
iCol = $.jgrid.getCellIndex($td[0]),
colModel = $(this).jqGrid("getGridParam", "colModel");
if (iCol >= 0 && $target.is(":checkbox")) {
if (colModel[iCol].name == "W3LabelSelected") {
console.log(colModel[iCol].name);
$(this).setSelection(rowid, true);
$(this).jqGrid('resetSelection');
$(this).jqGrid('saveRow', rowid, {
succesfunc: function (response) {
$grid.trigger('reloadGrid');
return true;
}
});
}
}
return true;
},
Configuration:
jqGrid version: Latest free jqGrid
Data Type: Json being saved to server
Minimal Grid Code: jsFiddle
EDIT: After Oleg's answer this is what I have so far:
beforeSelectRow: function (rowid, e) {
var $self = $(this),
iCol = $.jgrid.getCellIndex($(e.target).closest("td")[0]),
cm = $self.jqGrid("getGridParam", "colModel");
if (cm[iCol].name === "W3LabelSelected") {
//console.log($(e.target).is(":checked"));
$(this).jqGrid('saveRow', rowid, {
succesfunc: function (response) {
$grid.trigger('reloadGrid');
return true;
}
});
}
return true; // allow selection
}
This is close to what I want. However if I select on the checkbox the first time and the second time, the console.log does get called everytime. However the saveRow gets called only when I check the checkbox and then click on it again to uncheck it the first time and never after that. By default the checkbox can be checked or unchecked based on data sent from server.
In the image, the request is sent after selecting the checkbox two times instead of being sent everytime.
UPDATE: As per #Oleg's suggestion, I have implemented cellattr and called a function inside. In the function I simply pass the rowid and update the checkbox of that rowid on the server.
Here's the code I used:
{
name: 'W3LabelSelected',
index: 'u.W3LabelSelected',
align: 'center',
width: '170',
editable: false,
edittype: 'checkbox',
formatter: "checkbox",
search: false,
formatoptions: {
disabled: false
},
editoptions: {
value: "1:0"
},
cellattr: function (rowId, tv, rawObject, cm, rdata) {
return ' onClick="selectThis(' + rowId + ')"';
}
},
and my selectThis function:
function selectThis(rowid) {
$.ajax({
type: 'POST',
url: myurl,
data: {
'id': rowid
},
success: function (data) {
if (data.success == 'success') {
$("#list").setGridParam({
datatype: 'json',
page: 1
}).trigger('reloadGrid');
} else {
$("<div title='Error' class = 'ui-state-error ui-corner-all'>" + data.success + "</div>").dialog({});
}
}
});
}
FIDDLE
I think there is a misunderstanding in the usage of formatter: "checkbox", formatoptions: { disabled: false }. If you creates non-disabled checkboxs in the column of the grid in the way then the user just see the checkbox, which can be clicked and which state can be changed. On the other side nothing happens if the user changes the state of the checkbox. On the contrary the initial state of the checkbox corresponds to input data of the grid, but the changed checkbox makes illusion that the state is changed, but nothing will be done automatically. Even if you use datatype: "local" nothing is happens and even local data will be changed on click. If you do need to save the changes based on the changing the state of the checkbox then you have to implement additional code. The answer demonstrates a possible implementation. You can change the state of some checkboxes on the corresponding demo, then change the page and go back to the first page. You will see that the state of the checkbox corresponds the lates changes.
Now let us we try to start inline editing (start editRow) on select the row of the grid. First of all inline editing get the values from the rows (editable columns) using unformatter, saves the old values in internal savedRow parameter and then it creates new editing controls inside of editable cells on the place of old content. Everything is relatively easy in case of using standard disabled checkbox of formatter: "checkbox". jqGrid just creates enabled checkboxs on the place of disabled checkboxs. The user can change the state of the checkboxs or the content of any other editable columns and saves the changes by usage of Enter for example. After that the selected row will be saved and will be not more editable. You can monitor the changes of the state of the checkbox additionally (by usage editoptions.dataEvents with "change" event for example) and call saveRow on changing the state. It's important that the row will be not editable after the saving. If you do need to hold the row editable you will have to call editRow once more after successful saving of the row. You can call editRow inside of aftersavefunc callback of saveRow, but I recommend you to wrap the call of editRow inside of setTimeout to be sure that processing of previous saving is finished. It's the way which I would recommend you.
On the other side if you try to combine enabled checkboxs of formatter: "checkbox" with inline editing then you will have much more complex processing. It's important that enabled checkbox can be changed first of all before processing of onclick and onchange event handlers. The order of 3 events (changing the state of the checkbox, processing of onclick and processing of onchange) can be different in different web browsers. If the method editRow be executing it uses unformatter of checkbox-formatter to get the current state of the checkbox. Based of the value of the state editRow replace the content of the cell to another content with another enabled checkbox. It can be that the state of the checkbox is already changed, but editRow interprets the changes state like the initial state of the checkbox. In the same way one can call saveRow only after editRow. So you can't just use saveRow inside of change handler of formatter: "checkbox", formatoptions: { disabled: false }, because the line is not yet in editing mode.
UPDATED: The corresponding implementation (in case of usage formatter: "checkbox", formatoptions: { disabled: false }) could be the following:
editurl: "SomeUrl",
beforeSelectRow: function (rowid, e) {
var $self = $(this),
$td = $(e.target).closest("tr.jqgrow>td"),
p = $self.jqGrid("getGridParam"),
savedRow = p.savedRow,
cm = $td.length > 0 ? p.colModel[$td[0].cellIndex] : null,
cmName = cm != null && cm.editable ? cm.name : "Quantity",
isChecked;
if (savedRow.length > 0 && savedRow[0].id !== rowid) {
$self.jqGrid("restoreRow", savedRow[0].id);
}
if (cm != null && cm.name === "W3LabelSelected" && $(e.target).is(":checkbox")) {
if (savedRow.length > 0) {
// some row is editing now
isChecked = $(e.target).is(":checked");
if (savedRow[0].id === rowid) {
$self.jqGrid("saveRow", rowid, {
extraparam: {
W3LabelSelected: isChecked ? "1" : "0",
},
aftersavefunc: function (response) {
$self.jqGrid("editRow", rowid, {
keys: true,
focusField: cmName
});
}
});
}
} else {
$.ajax({
type: "POST",
url: "SomeUrl", // probably just p.editurl
data: $self.jqGrid("getRowData", rowid)
});
}
}
if (rowid) {
$self.jqGrid("editRow", rowid, {
keys: true,
focusField: cmName
});
}
return true; // allow selection
}
See jsfiddle demo http://jsfiddle.net/OlegKi/HJema/190/
Take a look at the following code:
this.dialog({
width: 500,
height: 260,
title: "Setup database",
content: $("<form>").append(table),
buttons: {
submit: function(_alert, dialog) {
dialog.find("form").each(function() {
var arr = $(this).serializeArray();
var data = {
mysql: true
};
var empty = false;
$(this).find("input").removeClass("error");
for (var k in arr) {
if ($.trim(arr[k].value) !== "") {
data[arr[k].name] = arr[k].value;
} else {
empty = true;
$(this).find("input[name='" + arr[k].name + "']").each(function() {
$(this).addClass("error");
});
break;
}
}
if (!empty) {
self.ajax({
url: url,
data: data
}, function(result) {
callback(result);
}, function() {
self.mysql(url, callback, _db_name, _db_user, _db_pass, is_dialog);
});
}
_alert.remove();
if($.isFunction(callback_submit)) {
callback_submit();
}
});
}
}
});
There are two parameters passed into the anonymous function that is supposed to trigger when the button "submit" is clicked. But I have no idea where these parameters are supposed to come from. Can someone explain? Is this related to passing parameters to an anonymous function in Javascript in general?
I don't think you get any argument passed to you when a button event callback is fired on jquery-ui dialog box
http://jsfiddle.net/3d7QC/1577/
buttons: {
"I've read and understand this": function() {
console.log(arguments);
// look at your console
$(this).dialog("close");
}
Only argument you get passed through to you is the customary jQuery event object.
There should only be one parameter passed to submit, which is the event object of the button itself, when clicked. So the context set is the submit button, if you need to access the dialog and modify it, you can do so by accessing the event.target property.
this.dialog({
buttons: {
submit: function(event) {
$(event).dialog('close'); //is the same as...
$(this).dialog('close');
}
});
The first argument _alert is the JS event object that is passed to every event handler in JavaScript. This is not specific to jQuery. javascript.info explains this as follows:
W3C way
Browsers which follow W3C standards always pass the event object as
the first argument for the handler.
For instance:
element.onclick = function(event) {
// process data from event
}
In the jQueryUI API reference they confirm that i
Specifies which buttons should be displayed on the dialog. The context
of the callback is the dialog element; if you need access to the
button, it is available as the target of the event object.
I illustrated this in a fiddle. Not sure what the second argument (dialog in your case) does, though. It's not passed in my example code.
I've written a program that includes a form that the user interacts with. Because there are lots of events bound to different buttons I have written a loop that parses some JS that contains the form input information. Here is some example data:
var value = 0,
forms = {
place_controls : {
attrs : {
'class' : 'place-form'
},
input : {
place_x : {
attrs : {
type : 'text',
},
events : {
change : function () {
value = 10;
}
}
},
place_y : {
attrs : {
type : 'text',
},
events : {
change : function () {
value = 50
}
}
}
}
}
}
The data is then parsed by this:
$.each(forms, function (form_index, form) {
var $form_markup = $('<form>').attr(form.attrs);
// Next: loop through each input element of the form we've reached
$.each(form.input, function (element_index, element) {
var $elem = $('<input>').attr(element.attrs);
$elem.appendTo($form_markup);
if (element.events !== undefined) {
$.each(element.events, function (event_index, event) {
$elem.bind(event_index, event);
//$form_markup.on(event_index, $elem, event);
});
}
});
$form_markup.appendTo($form_goes_here);
});
As you can see, I'm using .bind() at the moment, however I want to use .on(). Unfortunately, when I do this all of the items within a form are bound to the last event parsed by the function. When I use .bind() everything works as planned - i.e. Clicking on 'place_x' sets value to 10, clicking 'place_y' sets value to 50.
When using .on(), whichever I change sets value to 50, which I am assuming is because the last function is becoming bound to each event.
Can anybody see what I have done wrong?
Update: There are many different ways to do this, and I have subsequently changed how my code works, however this question is related to why .bind() is working and why .on() is not.
//$elem.bind(event_index, event);
//It looks like you should just be using .on() like this
$elem.on(event_index, event);
The way it looks like you are trying to use .on() is in the live -bubbling- event sort of way, it looks like only the last event you are created is sticking, why each value just gets set to 50.
//$form_markup.on(event_index, $elem, event);
You can create elements with property maps that include handler functions in one simple call:
var $elem = $('<input/>', properties);
The "properties" object can contain event handlers:
var $elem = $('<input/>', {
type: 'text',
name: 'somethingUseful',
click: function(ev) { /* click handler */ },
change: function(ev) { /* change handler */ },
css: { color: "red" }
});