How to disable a custom DataTables button in its action callback? - javascript

This is in a C# ASP.NET MVC 5 web application, using DataTables version 1.10.22.
I configure a DataTable to have a custom button. The action for the button is a callback function. After that function executes once, I want to disable the button.
I can disable all buttons associated with the DataTable. But, how do I disable just one button?
The DataTables documentation, such as https://datatables.net/reference/api/buttons().disable(), has an example that seems to identify certain buttons by... their CSS class name?
var table = $('#myTable').DataTable();
var buttons = table.buttons( ['.edit', '.delete'] );
buttons.disable();
But, how do I uniquely identify my custom button?
The action callback function for the button seems to be provided with several parameters that represent the button. But, the node does not seem to have a disable() function. Changing config.enabled to false has no effect. What else can I try?
The following is what I am trying to do in my Views/Foo/Index.cshtml:
<script>
$( document ).ready( onReady );
function onReady()
{
var config = {};
config.buttons =
[
// A button to create data for the table.
{
text: '<span class="fa fa-plus"/>',
titleAttr: 'Create states',
action: createStates,
enabled: true,
}
... other buttons ...
];
... other configuration ...
$( '#state-table' ).DataTable( config ) );
}
/**
* Create the states.
*
* Parameters:
* e (object): The event.
* table (object): The DataTable.
* node (jQuery): The jQuery instance of the button that was clicked.
* config (object): The button configuration.
*/
function createStates( e, table, node, config )
{
//------------------------------
// Create client-side state data in the table.
table.clear();
for ( var i = 0; i < 3; i++ )
{
var data = { Id: i, Name: 'state ' + i };
table.row.add( data );
}
//------------------------------
// Calling draw() at the end updates the DataTable internal caches.
table.rows().draw();
//------------------------------
// Disable the button, so that states cannot be created again.
// *** How ? ***
// Just changing this property has no effect on the button.
config.enabled = false;
// This disables all buttons, not just the one I want.
table.buttons().disable();
}
</script>

Each DataTables button can be given a button name and/or a class name - and then you can refer to that button using either of these - for example:
$(document).ready(function() {
var table = $('#myTable').DataTable( {
dom: 'Bfrtip',
"buttons": [
{
text: 'My Button',
className: 'myButtonClass',
name: 'myButtonName'
}
]
} );
table.buttons( '.myButtonClass' ).disable();
//table.buttons( 'myButtonName:name' ).disable();
});
In the above example, the button has both a button name and a class name.
There are various additional ways to select one or more buttons:
buttons( selector );
These selector options are documented here.
And, yes, that example in your question...
var buttons = table.buttons( ['.edit', '.delete'] );
...is indeed using the class name selector.

Related

How to make a code reusable in jQuery?

In my WordPress' projects, I'm using the following code again and again for many of my fields where I'm using a button to initiate the WordPress media uploader and on selection of the file I'm sending its path/url to a text field.
var project_field_image_uploader;
$('#button-input').click( function(e) {
e.preventDefault();
//if the uploader object has already been created, reopen the dialog
if( project_field_image_uploader ) {
project_field_image_uploader.open();
return;
}
//extend the wp.media object
project_field_image_uploader = wp.media.frames.file_frame = wp.media( {
title:"Choose an image",
button:{
text: "Insert"
},
multiple: false
} );
//when a file is selected, grab the URL and set it as the text field's value
project_field_image_uploader.on( 'select', function() {
attachment = project_field_image_uploader.state().get('selection').first().toJSON();
$('#text-field').val(attachment.url);
});
//Open the uploader dialog
project_field_image_uploader.open();
});
For each of the field I need to edit the following things:
First variable - project_field_image_uploader (not necessarily it should be meaningful, it is only for creating different instances, so in a reusable way, it can be anything, but not conflicting)
Button's ID - $('#button-input')
Text field's ID - $('#text-field')
Media Library Modal's head - title:"Choose an image",
Media Library's Media Insertion button's text - text: "Insert"
Is there a way I can make this code reusable, so that I can be with DRY ideology? A jQuery function may do the job for me, but I cannot sort things out, how can I sort this thing.
<script>
$(function(){
$('#button-input').click(function(e){
var text_field = $('#text-field');
....................
var mytext = 'my text';
myfunc(e,project_field_image_uploader,text_field,mytitle,mytext);
});
//reuse with any other button click with different parameters
});
function myfunc(e,project_field_image_uploader,text_field,mytitle,mytext){
e.preventDefault();
//if the uploader object has already been created, reopen the dialog
if( project_field_image_uploader ) {
project_field_image_uploader.open();
return;
}
//extend the wp.media object
project_field_image_uploader = wp.media.frames.file_frame = wp.media( {
title:mytitle,
button:{
text: mytext
},
multiple: false
} );
//when a file is selected, grab the URL and set it as the text field's value
project_field_image_uploader.on( 'select', function() {
attachment = project_field_image_uploader.state().get('selection').first().toJSON();
text_field.val(attachment.url);
});
//Open the uploader dialog
project_field_image_uploader.open();
}
</script>
Thanks to #alamnaryab for his answer that directed me to the right way (+1 for that). But passing a variable as a function parameter was problematic. It produces an error:
project_field_image_uploader is not defined
I figured out things that, a variable need not to pass as a function parameter to be unique, because a variable inside a function is a local variable. So I simply called the variable inside the function and reused the function multiple times. I'm here posting the working example code.
And declaring multiple variables, I used comma with a single var declaration. There's no need to repeat things. Thanks again to Mr. Alam Naryab.
<script>
$(function(){
$('#button-input').click(function(e){
var text_field = $('#text-field'),
media_lib_head = 'Choose an image',
btn_text = 'Insert';
//using the function where necessary
project_reusable_repeating_func( e, text_field, media_lib_head, btn_text );
});
});
/**
* Reusable function
* #author alamnaryab
* #link http://stackoverflow.com/a/32035149/1743124
*/
function project_reusable_repeating_func( e, text_field, media_lib_head, btn_text ){
//a variable that need not to be unique, because it's local
var project_field_image_uploader;
e.preventDefault();
//if the uploader object has already been created, reopen the dialog
if( project_field_image_uploader ) {
project_field_image_uploader.open();
return;
}
//extend the wp.media object
project_field_image_uploader = wp.media.frames.file_frame = wp.media( {
title: media_lib_head,
button:{
text: btn_text
},
multiple: false
} );
//when a file is selected, grab the URL and set it as the text field's value
project_field_image_uploader.on( 'select', function() {
attachment = project_field_image_uploader.state().get('selection').first().toJSON();
text_field.val(attachment.url);
});
//Open the uploader dialog
project_field_image_uploader.open();
}
</script>

Hide Approve/Reject Buttons in Fiori Master Details Page

I am looking to hide the Approve/Reject Buttons in the Details Page of a Fiori App based on certain filter conditions. The filters are added in the Master List view (Left hand side view) thru the view/controller extension.
Now, if the user selects certain type of filter ( Lets say, Past Orders) - then the approve/reject button should not be displayed in the Order Details Page.
This is how I have defined the buttons in the Header/Details view
this.oHeaderFooterOptions = {
oPositiveAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_APPROVE"),
id :"btn_approve",
onBtnPressed: jQuery.proxy(that.handleApprove, that)
},
oNegativeAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_REJECT"),
id :"btn_reject",
onBtnPressed: jQuery.proxy(that.handleReject, that)
},
However at runtime, these buttons are not assigned the IDs I mentioned, instead they are created with IDs of __button0 and __button1.
Is there a way to hide these buttons from the Master List View?
Thank you.
Recommended:
SAP Fiori design principles only talk about disabling the Footer Buttons instead of changing the visibility of the Button.
Read More here about Guidelines
Based on filter conditions, you can disable like this:
this.setBtnEnabled("btn_approve", false);
to enable again: this.setBtnEnabled("btn_approve", true);
Similarly you can change Button text using this.setBtnText("btn_approve", "buttonText");
Other Way: As #TobiasOetzel said use
this.setHeaderFooterOptions(yourModifiedHeaderFooterOptions);
you can call setHeaderFooterOptions on your controller multiple times eg:
//Code inside of the controller
_myHeaderFooterOptions = {
oPositiveAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_APPROVE"),
id :"btn_approve",
onBtnPressed: jQuery.proxy(that.handleApprove, that)
},
oNegativeAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_REJECT"),
id :"btn_reject",
onBtnPressed: jQuery.proxy(that.handleReject, that)
}
},
//set the initial options
onInit: function () {
this.setHeaderFooterOptions(this._myHeaderFooterOptions);
},
//modify the options in an event
onFilter : function () {
//remove the negative action to hide it
this._myHeaderFooterOptions.oNegativeAction = undefined;
this.setHeaderFooterOptions(this._myHeaderFooterOptions);
},
//further code
so by manipulating the _myHeaderFooterOptions you can influence the displayed buttons.
First, you should use sId instead id when defining HeaderFooterOptions, you can get the footer buttons by sId, for example, the Approve button.
this._oControlStore.oButtonListHelper.mButtons["btn_approve"]
Please check the following code snippet:
S2.view.controller: You have a filter event handler defined following and use EventBus to publish event OrderTypeChanged to S3.view.controller.
onFilterChanged: function(oEvent) {
// Set the filter value, here i use hard code
var sFilter = "Past Orders";
sap.ui.getCore().getEventBus().publish("app", "OrderTypeChanged", {
filter: sFilter
});
}
S3.view.controller: Subscribe event OrderTypeChanged from S2.view.controller.
onInit: function() {
///
var bus = sap.ui.getCore().getEventBus();
bus.subscribe("app", "OrderTypeChanged", this.handleOrderTypeChanged, this);
},
getHeaderFooterOptions: function() {
var oOptions = {
oPositiveAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_APPROVE"),
sId: "btn_approve",
onBtnPressed: jQuery.proxy(that.handleApprove, that)
},
oNegativeAction: {
sI18nBtnTxt: that.resourceBundle.getText("XBUT_REJECT"),
sId: "btn_reject",
onBtnPressed: jQuery.proxy(that.handleReject, that)
}
};
return oOptions;
},
handleOrderTypeChanged: function(channelId, eventId, data) {
if (data && data.filter) {
var sFilter = data.filter;
if (sFilter == "Past Orders") {
this._oControlStore.oButtonListHelper.mButtons["btn_approve"].setVisible(false);
}
//set Approve/Reject button visible/invisible based on other values
//else if(sFilter == "Other Filter")
}
}

Redefining a jQuery dialog button

In our application we use a general function to create jQuery dialogs which contain module-specific content. The custom dialog consists of 3 buttons (Cancel, Save, Apply). Apply does the same as Save but also closes the dialog.
Many modules are still using a custom post instead of an ajax-post. For this reason I'm looking to overwrite/redefine the buttons which are on a specific dialog.
So far I've got the buttons, but I'm unable to do something with them. Is it possible to get the buttons from a dialog (yes, I know) but apply a different function to them?
My code so far:
function OverrideDialogButtonCallbacks(sDialogInstance) {
oButtons = $( '#dialog' ).dialog( 'option', 'buttons' );
console.log(oButtons); // logs the buttons correctly
if(sDialogInstance == 'TestInstance') {
oButtons.Save = function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
}
}
}
$('#dialog').dialog({
'buttons' : {
'Save' : {
id:"btn-save", // provide the id, if you want to apply a callback based on id selector
click: function() {
//
},
},
}
});
Did you try this? to override button's callback based on the need.
No need to re-assign at all. Try this.
function OverrideDialogButtonCallbacks(dialogSelector) {
var button = $(dialogSelector + " ~ .ui-dialog-buttonpane")
.find("button:contains('Save')");
button.unbind("click").on("click", function() {
alert("save overriden!");
});
}
Call it like OverrideDialogButtonCallbacks("#dialog");
Working fiddle: http://jsfiddle.net/codovations/yzfVT/
You can get the buttons using $(..).dialog('option', 'buttons'). This returns an array of objects that you can then rewire by searching through them and adjusting the click event:
// Rewire the callback for the first button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons[0].click = function() { alert('Click rewired!'); };
See this fiddle for an example: http://jsfiddle.net/z4TTH/2/
If necessary, you can check the text of the button using button[i].text.
UPDATE:
The buttons option can be one of two forms, one is an array as described above, the other is an object where each property is the name of the button. To rewire the click event in this instance it's necessary to update the buttons option in the dialog:
// Rewire the callback for the OK button
var buttons = $('#dialog').dialog('option', 'buttons');
buttons.Ok = function() { alert('Click rewired!'); };
$('#dialog').dialog('option', 'buttons', buttons);
See this fiddle: http://jsfiddle.net/z4TTH/3/
Can you try binding your new function code with Click event of Save?
if(sDialogInstance == 'TestInstance') {
$('#'+savebtn_id).click(function() {
alert('A new callback has been assigned.');
// code for ajax-post will come here.
});
}

EXtJS grid CheckColumn, How to execute function, after column is clicked/its state is checked?

I have ExtJS GRID with checkcolumn, which is declared this way:
// the check column is created using a custom plugin
sel_column = new Ext.grid.CheckColumn({
sortable: false,
header: 'STE<br />SEL',
dataIndex: 'sel',
width: field_w,
listeners:
{
"mousedown":
{
fn : function(e)
{
$.log( "Sel cellclick" , e );
}
}
}
});
I want add some listener on changfe of it stae, or on mouse click.
Finaly - want id's of rows, where i click this column - to be stored in text field
For now i can understood how to catch click event, i use onMouseDown, this way:
// the check column is created using a custom plugin
sel_column = new Ext.grid.CheckColumn({
sortable: false,
header: 'STE<br />SEL',
dataIndex: 'sel',
width: field_w,
onMouseDown: function( e )
{
$.log( e,"MouseDown" );
}
});
But it fires, when i click ANY cell, not only checkboxed ...
Pls help me
checkbox plugin need modification, after which it can fire click event.
/*
**************************************************************
Sample to add event 'checkchange' in checkbox on checkcolumn,
works with ExtJS 4 or above
*/
//Add you checkcolumn id:'op_check'. No need separate plugin.
//Put this code in You Grid
listeners:{
afterrender:function(){
g = this; //This grid
Ext.getCmp('op_check').on('checkchange', function(c, i){
//Get id from row/record (if in store exist field 'id')
//"i" - in this function is index row, where clicked checkbox
rec = g.store.getAt(i);
id = rec.get('id');
console.log(id); //:)
});
}
}

ckeditor add event handler to dialog element

I'm writing a custom dialog/plugin for ckeditor. What I want to know is how I can add an eventlistener to a select box in the dialog, to alert when the selected value has been changed. How can I do this?
I've looked at the API and I've come across some useful information but it is not detailed enough. I can't make a connection between the API information and what I am trying to implement.
The select elements in the dialogs automatically fire a change event when they are changed. You can add an onChange function in the definition for the select element. Here's an example from the api:
onChange : function( api ) {
// this = CKEDITOR.ui.dialog.select
alert( 'Current value: ' + this.getValue() );
}
These pages have examples for creating definitions used by dialogs and ui elements:
Class CKEDITOR.dialog
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.html
Class CKEDITOR.dialog.definition
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.definition.html
Class CKEDITOR.dialog.definition.select
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.definition.select.html
If you would like to listen for a change to a select element from another location, you can create a listener that keys on the "dialogShow" event. Here's an example:
// Watch for the "dialogShow" event to be fired in the editor,
// when it's fired, perform this function
editor.on( 'dialogShow', function( dialogShowEvent )
{
// Get any data that was sent when the "fire" method fired the dialogShow event
var dialogShowEventData = dialogShowEvent.data;
// Get the dialog name from the array of data
// that was sent when the event was fired
var currentDialogName = dialogShowEventData._.name;
alert( currentDialogName );
// Create a reference to a particular element (ELEMENT-ID)
// located on a particular tab (TAB-ID) of the dialog that was shown.
var selectorObj = dialogShowEventData._.contents.TAB-ID.ELEMENT-ID;
// Watch for the "change" event to be fired for the element you
// created a reference to (a select element in this case).
selectorObj.on( 'change', function( changeEvent )
{
alert("selectorObj Changed");
});
});
You can check if the dialog you want to work with is the one that fired the "dialogShow" event. If so, you can create an object for the select element you're interested in and listen for a "change" event.
Note: the TAB-ID and ELEMENT-ID placeholders I used do not refer to the Id attribute of the element. The Id refers to the Id assigned in the dialog definition file. The Id attribute for the various elements are different each time the dialog is loaded.
This page has some info on events:
Class CKEDITOR.event
http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.event.html
Be Well,
Joe
Answers to additional questions asked in comments:
Q1) Your event here is 'dialogShow', what other events are allowed? i.e are they pre-defined or user defined?
A1) The 'dialogShow' event is predefined. You can look at the file containing the dialogs code in your CKEditor install directory or on the website:
ckeditor\_source\plugins\dialog\plugin.js
http://docs.cksource.com/ckeditor_api/symbols/src/plugins_dialog_plugin.js.html
If you search the file for 'fire', you'll see all the events that are fired for dialogs. The end of the file has definitions for the various events.
You can also define your own events to key on by using the "fire" method in your dialog code:
this.fire( 'yourEventNameHere', { yourPropertyOne : "propertyOneValue", yourPropertyTwo : "propertyTwoValue" } );
Then watch for it:
editor.on( 'yourEventNameHere', function( eventProperties )
{
var propOne = eventProperties.data.yourPropertyOne; // propOne = "propertyOneValue"
var propTwo = eventProperties.data.yourPropertyTwo; // propTwo = "propertyTwoValue"
Do something here...
});
Q2) Can you explain the syntax dialogShowEventData._.name ? I've seen it before but i don't know the significance, something to do with private variables?
A2) For anyone wondering about the "._." syntax used in the CKEditor code, it's used to reduce the size of the code and replaces ".private." See this post by #AlfonsoML in the CKEditor forum:
http://cksource.com/forums/viewtopic.php?t=22982
Q3) Where can i get more info on TAB-ID.ELEMENT-ID?
A3) The Tab-ID is the id that you assign to a particular tab (pane) of a dialog. ( see below: id : 'tab1', )
The Element-ID is the id that you assign to a particular element contained in a tab in your dialog. ( see below: id : 'textareaId', )
Look at this page: http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.dialog.html#.add
It shows how you define the tabs and elements contained in a dialog window ( I added an example of a select element that fires a user defined event ):
var dialogDefinition =
contents : [
{
id : 'tab1',
label : 'Label',
title : 'Title',
expand : true,
padding : 0,
elements :
[
{
type : 'html',
html : '<p>This is some sample HTML content.</p>'
},
{
type : 'textarea',
id : 'textareaId',
rows : 4,
cols : 40
},
// Here's an example of a select element:
{
type : 'select',
id : 'sport',
label : 'Select your favourite sport',
items : [ [ 'Basketball' ], [ 'Baseball' ], [ 'Hockey' ], [ 'Football' ] ],
'default' : 'Football',
onChange : function( api ) {
// this = CKEDITOR.ui.dialog.select
alert( 'Current value: ' + this.getValue() );
// CKEditor automatically fires a "change" event here, but
// here's an example of firing your own event
this.fire( 'sportSelector', { sportSelectorPropertyOne : "propertyOneInfo" } );
}
]
}
],
Q4) Can you briefly explain what the above code is doing?
A4) See the original code, I've added comments.
You can use blur event of the editor, it is being fired whenever the window is opened.
editor.on( 'blur', function( dialogShowEvent ) {
//Add your logic here for the change event of select element
});

Categories