I'm trying to copy a specific cell from an Interactive Grid (which is in Display Only mode, if that matters), and instead of copying the cell I'm in, I'm copying the whole row. I can't seem to find any way to copy just the cell.
APEX versiĆ³n: Application Express 19.1.0.00.15
Thank you beforehand.
Oracle Apex does not enable copy functionality to interactive report by purpose.
To enable it, you need to use even handler for copy event. This handler should be on the body or document. It can be achieved through Dynamic Action :
Event: Custom
Custom Event: copy
Selection Type: jQuery Selector
jQuery Selector: body
Then add one JavaScript true action with below code:
var text, i, selection, gridSel;
var event = this.browserEvent.originalEvent; // need the clipboard event
// we only care about copy from a grid cell ignore the rest
if ( !$(document.activeElement).hasClass("a-GV-cell") ) {
return;
}
var view = apex.region("emp").widget().interactiveGrid("getCurrentView"); //change "emp" to you IG static id
if ( view.internalIdentifier === "grid") {
text = "";
selection = window.getSelection();
gridSel = view.view$.grid("getSelection");
for (i = 0; i < gridSel.length; i++) {
selection.selectAllChildren(gridSel[i][0]);
text += selection.toString();
if (gridSel[i].length > 1) {
selection.selectAllChildren(gridSel[i][1]);
text += " \t" + selection.toString();
}
text += "";
}
selection.removeAllRanges();
event.clipboardData.setData('text/plain', text);
event.preventDefault();
}
The above will copy the current grid selection to the clipboard when the user types Ctrl+C while in a grid cell.
I wonder if the below javascript can be modified in order to trigger 'toggle' actions of interactive grid such 'selection-mode'.
apex.region( "[region static ID] " ).call( "getActions" ).lookup( "[action name]" );
Reference:
https://docs.oracle.com/en/database/oracle/application-express/20.1/aexjs/interactiveGrid.html
If someone is interested, I managed to find the solution.
Go on Interactive Grid's attributes--> JavaScript Initialization Code
and add the following code that creates a button that copies the selected cell.
function(config) {
let $ = apex.jQuery,
toolbarData = $.apex.interactiveGrid.copyDefaultToolbar(),
toolbarGroup3 = toolbarData.toolbarFind("actions3");
toolbarGroup3.controls.push({type: "BUTTON",
label: "Copy cell",
icon: "fa fa-copy is-blue",
iconBeforeLabel: true,
iconOnly: false,
disabled: false,
action: "custom-event" // instead of specific action eg "selection-copy", create a custom event
});
config.initActions = function( actions ) {
actions.add( {
name: "custom-event",
action: function(event, focusElement) {
actions.lookup('selection-mode').set(false); // select cell instead of the whole row
apex.region( "users_id" ).widget().interactiveGrid( "getActions" ).invoke( "selection-copy" ); // copy the selection
actions.lookup('selection-mode').set(true); // select again the whole row (important in case of master-detail grids)
}
} );
}
config.toolbarData = toolbarData;
return config;
}
Related
CKEditor v4.8 Question with SharedSpaces. I am dynamically generating the Editors (with content replacing the DIV tags - inline editing) in a loop based on SQL rows.
I would like to only load/call the editor.ui.addButton and addRichCombo once outside of the loop. Is this possible?
for (var i = 0; i < retrievedRecords.length; i++) {
var documentBlock = retrievedRecords[i];
// This next line creates each inline editor with all custom buttons and combo every time through the loop
// Can I just load the custom buttons and combo once and all new editors use that 1 toolbar?
createInlineEditor('myID_' + i, content, id);
var refToEditor = document.getElementById('myID_' + i);
divContainer.appendChild(refToEditor);
}
sharedspace plugin works little different than you would think. It doesn't share the same toolbar between editors, but it's the space between the top and bottom toolbars. I know it could sound little complicated so I'm adding some image to illustrate it:
There are some important reasons why it works like that, but the most obvious is that you can have different plugins for your editors with configured sharedspace plugin and they change the appearance of the toolbar e.g. by additional buttons. If you could share the same toolbar you could get not working buttons for different editors.
IMO the best thing you can do to simplify your code is sharing configuration object between editors.
var config = {
on: {
pluginsLoaded: function( evt ) {
evt.editor.ui.addButton( 'MyBold', {
label: 'My Bold',
command: 'bold',
toolbar: 'basicstyles,1'
} );
}
}
};
for (var i = 0; i < retrievedRecords.length; i++) {
var documentBlock = retrievedRecords[i];
var editor = createInlineEditor('myID_' + i, content, id, config);
var refToEditor = document.getElementById('myID_' + i);
divContainer.appendChild(refToEditor);
}
Anyone please tell me how can i select next consecutive row from first page to second page of my kendo grid and reverse back to the previous page ? Kendo Grid API just only gives me information on 'select' and from there I have no clue at all how to implement my desired selection. What I have now is only selecting the row of the selected/active cell. Any insight/references are also appreciated. So far I haven't came across with any examples or article.
var data = $("#grid").data('kendoGrid');
var arrows = [38,40];
data.table.on("keydown", function (e) {
if (arrows.indexOf(e.keyCode) >= 0) {
setTimeout(function () {
data.clearSelection();
data.select($("#grid_active_cell").closest("tr"));
},1);
}
});
http://dojo.telerik.com/eSUQO
var data = $("#grid").data('kendoGrid');
var arrows = [38,40];
var navrow_uid; ** add this tracking variable;
data.table.on("keydown", function (e) {
if (arrows.indexOf(e.keyCode) >= 0) {
setTimeout(function () {
data.clearSelection();
// break this up
// data.select($("#grid_active_cell").closest("tr"));
// fetch next row uid and compare to tracker
var nextrow = $("#grid_active_cell").closest("tr");
var uid = nextrow.data('uid');
if (navrow_uid == uid ) {
console.log("last navigable row");
data.dataSource.page(1+data.dataSource.page());
// best option here would be to set auto-page flag for databound event handler
} else {
data.select(nextrow);
navrow_uid = uid;
}
},1);
}
});
You will want to add a grid data bound handler, and have that check the aut-page flag to see if you need to select first or last row of page.
I am wondering if it is possible to disable a specific widget in the ToolBar in the 'editables' portion of the widget code? I currently have the below code set up for a widget. Within these selectors, I do not want the user adding in a specific widget in the ToolBar.
this.editables = {
content1: {
selector: '.content1',
allowedContent: this.allowedContent
},
content2: {
selector: '.content2',
allowedContent: this.allowedContent
},
content3: {
selector: '.content3',
allowedContent: this.allowedContent
}
};
I have tried adding in the below logic but it breaks my code.
var oWidget= editor.getCommand('customWidget')
oWidget.setState(CKEDITOR.TRISTATE_DISABLED);
Any advise would be much appreciated.
Thank you!
For this you need to check for user selection event, and if selection in editable portion enable command.
Something like this -
CKEDITOR.instances["textarea"].on( 'selectionChange', function( evt ) {
// get desired command from ckeditor
var myCommand = this.getCommand( 'CKEDITOR_COMMAND_NAME' );
var mySelection = null;
// check if something is selected
var mySelection = this.getSelection().getNative() || this.window.$.getSelection() || this.document.$.selection;
if (!mySelection) {
// if not stay disable
myCommand.disable();
} else {
//if yes enable command
myCommand.enable();
}
});
The SlickGrid supports editors for a cell that can be configured to be displayed on click or double click. However I don't see an option where, the editor is VISIBLE by default for all cells without having to click/double click on the cell.
Is it possible to support editors in slick grid where the editors are
"init" by default for all cells?
Is there a known workaround?
Thank you.
I know it's not exactly what you asked for, but I thought I'd add the code below in case anyone finds it useful. It's a semi-workaround and it at least lets the user navigate around the grid and start typing in the cell to edit, without having to "initialise" the edit first by pressing Enter or double-clicking the cell; a bit like editing an MS Excel sheet.
myGrid.onKeyDown.subscribe(function (e, args) {
var keyCode = $.ui.keyCode,
col,
activeCell = this.getActiveCell();
/////////////////////////////////////////////////////////////////////
// Allow instant editing like MS Excel (without presisng enter first
// to go into edit mode)
if (activeCell) {
col = activeCell.cell;
// Only for editable fields and not if edit is already in progress
if (this.getColumns()[col].editor && !this.getCellEditor()) {
// Ignore keys that should not activate edit mode
if ($.inArray(e.keyCode, [keyCode.LEFT, keyCode.RIGHT, keyCode.UP,
keyCode.DOWN, keyCode.PAGE_UP, keyCode.PAGE_DOWN,
keyCode.SHIFT, keyCode.CONTROL, keyCode.CAPS_LOCK,
keyCode.HOME, keyCode.END, keyCode.INSERT,
keyCode.TAB, keyCode.ENTER]) === -1) {
this.editActiveCell();
}
}
}
}
No. The grid is designed to have one cell editable at a time.
Below is what I ended up with (improved version njr101's answer) to make this work. I've added a check for CTRL key so it doesn't break the copy paste plugin I use on the grid.
function (e) {
var keyCode = $.ui.keyCode,
col,
activeCell = this.getActiveCell(),
activeCellNode = this.getActiveCellNode();
var isInEditMode = $(activeCellNode).hasClass("editable");
if (activeCell && !isInEditMode) {
col = activeCell.cell;
if (this.getColumns()[col].editor && !e.ctrlKey) {
if ($.inArray(e.keyCode, [keyCode.LEFT, keyCode.RIGHT, keyCode.UP,
keyCode.DOWN, keyCode.PAGE_UP, keyCode.PAGE_DOWN,
keyCode.SHIFT, keyCode.CONTROL, keyCode.CAPS_LOCK,
keyCode.HOME, keyCode.END, keyCode.INSERT,
keyCode.TAB, keyCode.ENTER]) === -1) {
this.editActiveCell();
}
}
}
};
and dont forget to subscribe:
slickGrid.onKeyDown.subscribe();
Update to use editor define in row metadata and not in column definition.
In my case, one row of two contains in cell 1 text editor and one row of two contains nothing.
grid.onKeyDown.subscribe( function ( e, args ) {
var keyCode = $.ui.keyCode;
var activeCell = this.getActiveCell();
if( activeCell ) {
// get metadata
var columnDefinition = grid.getColumns()[ activeCell.cell ];
var rowMetadata = dataView.getItemMetadata && dataView.getItemMetadata( activeCell.row );
var rowColMetadata = rowMetadata && rowMetadata.columns;
rowColMetadata = rowColMetadata && ( rowColMetadata[ columnDefinition.id ] || rowColMetadata[ activeCell.cell ] );
if ( rowColMetadata && rowColMetadata.editor && !this.getCellEditor() ) {
if( $.inArray( e.keyCode, [keyCode.LEFT, keyCode.RIGHT, keyCode.UP, keyCode.DOWN, keyCode.PAGE_UP, keyCode.PAGE_DOWN,
keyCode.SHIFT, keyCode.CONTROL, keyCode.CAPS_LOCK, keyCode.HOME, keyCode.END, keyCode.INSERT,
keyCode.TAB, keyCode.ENTER]) === -1 ) {
this.editActiveCell();
}
}
}
});
is there an example of using jqgrid's getChangedCells
method to determine if data has changed?
I grepped getChangedCells in the downloadable demos for
jqgrid, and could only find the function definition, not
example usages of getChangedCells.
What I want to do is save the edits that a user's
made if the user clicks on another row. But, I only
want to submit the save if the row is dirty.
Thanks in advance,
--Nate
There are no safe dirty flag on the row. You can use the fact that at the beginning of row editing (at the start of the inline editing mode) the method editRow add editable="1" attribute to the grid row (<tr> element). Later the methods saveRow and restoreRow changes the attribute value to editable="0". So the rows of the current page which was at least once in the inline editing mode will have the editable attribute. If the id of the table element is "list" you can find the edited rows with
$("#list tr[editable]")
The ids of the elements of the set are the rowids of the rows.
If you use paging in the grid you should be careful and save the ids of the edited rows on the current page before the changing of the page. The onPaging event would help you here.
In my opinion the best and the most safe way to do what you need is to use aftersavefunc parameter of the editRow or saveRow methods (probably you use directly only editRow). Inside of your aftersavefunc function you can save the id of the modified row in an array/map. This will solve your problem and will safe work.
Finally, I managed to bring a piece of code to detect what we want ;)
Hopefully any jqgrid gurus there (like Oleg), have enough time to review this code and improve it.
The example code will work for detect data changed in a grid with an editable field named "name". If you want to check for changed data in more columns, you have to add the variables after_edit and before_edit asociated with that columns.
To get the previous cell data inside the onSelectRow function, I don't used the getCell method because in the documentation says in red:
Do not use this method when you editing the row or
cell. This will return the cell content and not the
actuall value of the input element
By disgrace I could check that the documentation was right :(.
However the getCell function works properly with the current cell data.
And here is the code:
// Declare variables used for inline edit functionality.
var last_selected;
var before_edit_value;
var after_edit_value;
$('#grid-id').jqGrid({
...
onSelectRow: function(row_id){
if(row_id && row_id !== last_selected) {
/*
* Determine if the value was changed, if not there is no need to save to server.
*/
if (typeof(last_selected) != 'undefined') {
after_edit_value = $('#grid-id tr#' + last_selected + ' .name_column input').val();
}
if (before_edit_value != after_edit_value) {
/*
* Save row.
*/
$('#grid-id').jqGrid(
'saveRow',
last_selected,
function(response){
/* SuccessFunction: Do something with the server response */
return true;
},
'http://url.to.server-side.script.com/server-side-script.php',
{
additional_data: 'example: additional string',
});
}
else {
/*
* Restore the row.
*/
$('#grid-id').jqGrid('restoreRow', last_selected);
}
before_edit_value = $('#grid-id').jqGrid('getCell', row_id, 'name');
}
last_selected = row_id;
/*
* Edit row.
*/
$('#grid-id').jqGrid(
'editRow',
row_id,
true,
function() {/* OnEditFunction */},
function(response) {
/* SuccessFunction: Do something with the server response */
return true;
},
'http://url.to.server-side.script.com/server-side-script.php',
{
additional_data: 'example: additional string',
});
},
...
});
In one of my projects I did the following: before editing the row I remember row data in global variable and after editing is done just check if row data was changed. Something like this (edit mode activated by double click):
var beforeEditData;
function onGridDblClickRow(id) {
if (isRowEditable(id)) {
beforeEditData = grid.getRowData(id);
grid.editRow(id, true, null, null, 'clientArray', null, onRowAfterEdit);
...
}
}
function onRowAfterEdit(row) {
var data = grid.getRowData(row);
if (!isDataChanged(beforeEditData, data)) {
return; // No changes
}
... // Save data here
}
function isDataChanged(before, after){
... // Allows tricky logic for dirty data, e.g. one may trim spaces etc.
}
Using MVC4 and JQuery this is what I did
In the View
<script type="text/javascript">
var $grid = $("#Grid");
var lastSelection;
var datachanged = false;
function gridInitialised() {
var headers = $('th>div>:input');
for (var h = 0; h < headers.length; headers[h++].onclick = (function () { if (datachanged) { $grid.saveRow(lastSelection); datachanged = false; } }));
}
function editRow(id) {
if (id && id !== lastSelection) {
if (datachanged) { $grid.saveRow(lastSelection); datachanged = false; }
$grid.restoreRow(lastSelection);
$grid.editRow(id, true);
var inputs = $('#'+id+'>td>:input[class="editable"]');
for (var i = 0; i < inputs.length; inputs[i++].onchange = (function () { datachanged = true; }));
lastSelection = id;
}
}
</script>
#Html.Trirand().JQGrid(Model.Grid, "Grid")
in the Model
Grid.ClientSideEvents.RowSelect = "editRow";
Grid.ClientSideEvents.GridInitialized = "gridInitialised";
The gridInitialised code is to handle changes to the search filter.
Dave
As Oleg mentioned 5 (wow) years ago - I used the saveRow function and passed the flag as extraparam.
something like this, assuming your "model" or a hidden column IsDirty in my case:
onSelectRow: function(id) {
if (id && id !== lastgridsel) {
$("#myGrid").saveRow(lastgridsel, false, "clientArray", { IsDirty: "True" });
$("#myGrid").editRow(id, true, null, null, "clientArray");
lastgridsel = id;
}
},
and then loop through the rows on Save click (external button in my case), something along the lines of:
$("#gridSaveBtn").on("click", function() {
var batch = new Array();
var dataIds = $("#myGrid").jqGrid("getDataIDs");
for (var i = 0; i < dataIds.length; i++) {
try {
$("#myGrid").jqGrid("saveRow", dataIds[i], false, "clientArray");
//get row data
var data = $("#myGrid").jqGrid("getRowData", dataIds[i]);
if (data["IsDirty"] === "True") {
batch.push(data);
}
} catch (ex) {
alert(ex.Message);
$("#myGrid").jqGrid("restoreRow", dataIds[i]);
}
}
});