Observe sweetalert2 confirm with javascript in R Shiny - javascript

I have switched to sweetalert2 since the old version is more limited than the new version which is actively developped.
I am running into a problem however, the code I used to observe confirm or cancel in the old version is not working for me anymore.
In the old version I used to add a function in the 'myjava' code after
closeOnConfirm: true}
namely:
,
evalFunction = function(isConfirm){
if (isConfirm === true) {
var val1= 1;
Shiny.onInputChange('option1', [val1, Math.random()]);
}
else {
var val2= 2;
Shiny.onInputChange('option2'', [val2, Math.random()]);
}
}
but that doesn't work with sweetalert2 it seems.
I tried to try and make the examples on the site work but no luck. https://sweetalert2.github.io/
They use a structure like :
.then((result) => {
if (result.value === true) {
swal('Processing');
}
});
but it keeps resulting in a
Warning: Error in : shinyjs: Error parsing the JavaScript file: SyntaxError: Unexpected token >.
Here is the app to test it with. You will need to change the directory and download the two files to make sweetalert2 work
here: https://www.jsdelivr.com/package/npm/sweetalert2
download button is on the right of the title sweetalert2
and the 2 files needed are in the dist folder named:
sweetalert2.min.js & sweetalert2.min.css
setwd('FOLDER WHERE THE sweetalert2files are ')
library(shiny)
library(shinyjs)
myjava <- "shinyjs.swalFromButton = function(params) {
var defaultParams = {
title : null,
html : null
};
params = shinyjs.getParams(params, defaultParams);
swal({title : params.title, html : params.html,
showConfirmButton : true,
confirmButtonText : 'Left',
confirmButtonColor: '#00cc00',
showCancelButton : true,
cancelButtonText : 'Right',
cancelButtonColor : '#339fff',
closeOnCancel : true,
allowOutsideClick: true,
allowEscapeKey: true,
closeOnConfirm: true});
};"
ui <- fluidPage(
actionButton(inputId = 'messagebutton', label = 'click me'),
shinyjs::useShinyjs(),
shinyjs::extendShinyjs(text = myjava),
tags$head(includeScript("sweetalert2.min.js"),
includeCSS("sweetalert2.min.css")
)
)
server <- function(input, output, session) {
observeEvent(input$messagebutton, {
shinyjs::js$swalFromButton( title = paste('<span style ="color:#339FFF;">An alert with a choice'),
html = paste('Pick left or right'))
})
observeEvent(input$option1, { print('confirm choosen')})
observeEvent(input$option2, { print('cancel choosen')})
}
shinyApp(ui = ui, server = server)
UPDATE
I tried endless variations of this javascript, removing the problematic > symbol as was suggested, but R keeps throwing 'error parsing the javascript code provided.
myjava <- "shinyjs.swalFromButton = function(params) {
var defaultParams = {
title : null,
html : null
};
params = shinyjs.getParams(params, defaultParams);
swal({title : params.title, html : params.html,
showConfirmButton : true,
confirmButtonText : 'Left',
confirmButtonColor: '#00cc00',
showCancelButton : true,
cancelButtonText : 'Right',
cancelButtonColor : '#339fff',
closeOnCancel : true,
allowOutsideClick: true,
allowEscapeKey: true,
closeOnConfirm: true}).then((result){
if (result.value === true) {
swal('Processing');
}
});
};"

Thanks to Stéphane Laurents comments, this is the solution:
Including the means to send a variable back to R shiny.
myjava <- "shinyjs.swalFromButton = function(params) {
var defaultParams = {
title : null,
html : null
};
params = shinyjs.getParams(params, defaultParams);
swal({title : params.title, html : params.html,
showConfirmButton : true,
confirmButtonText : 'Left',
confirmButtonColor: '#00cc00',
showCancelButton : true,
cancelButtonText : 'Right',
cancelButtonColor : '#339fff',
closeOnCancel : true,
allowOutsideClick: true,
allowEscapeKey: true,
closeOnConfirm: true})
.then(function(result){
swal('succes');
if (result.value === true) {
var val1= true;
Shiny.setInputValue('option1', val1, {priority: "event"});}
else {
swal('failure');
var val2= true;
Shiny.setInputValue('option2', val2, {priority: "event"});}
});
};"

Related

allowOutsideClick not working in SweetAlert2

function show_alert(args) {
Swal.fire({
icon: args.icon,
title: args.title,
text: args.message,
html: args.html,
allowEscapeKey: args.allowEscapeKey ? args.allowEscapeKey : true,
allowOutsideClick: args.allowOutsideClick ? args.allowOutsideClick : true,
confirmButtonText: args.confirmButtonText ? args.confirmButtonText : 'Tamam',
confirmButtonColor: args.confirmButtonColor ? args.confirmButtonColor : '#3085d6',
cancelButtonText: args.cancelButtonText ? args.cancelButtonText : 'İptal',
cancelButtonColor: args.cancelButtonColor ? args.cancelButtonColor : '#d33',
showCancelButton: args.showCancelButton === undefined ? false : args.showCancelButton,
showCloseButton: args.showCloseButton === undefined ? false : args.showCloseButton,
showConfirmButton: args.showConfirmButton === undefined ? true : args.showConfirmButton,
didOpen: args.didOpen ? args.didOpen : null,
reverseButtons: true,
}).then((result) => {
if (result['isConfirmed']) {
args.callback ? args.callback_args ? args.callback(args.callback_args) : args.callback() : null;
} else if (result['isDismissed'] && args['isDismissed']) {
event.preventDefault();
args.isDismissed ? args.isDismissed() : null;
}
});
}
The above code block is a general alert display function. I can display alerts based on the parameters I give in "args".
I wrote the following code blocks to show a loading alert when the user clicks a button:
show_alert({
'title': 'Please wait',
'html': 'Loading audio file ...',
'allowEscapeKey': false,
'allowOutsideClick': false,
'showConfirmButton': false,
'showCancelButton': false,
'showCloseButton': false,
'didOpen': () => {Swal.showLoading();},
'isDismissed': () => {console.log('dismissed');}
});
However, when the user clicks anywhere on the page outside of the alert, the alert closes.
Is it possible to stop this by using a function like event.preventDefault()? If you can help, I would appreciate it.
In the "else if" block, I tried to catch the event and prevent the click event, like the "allowOutsideClick" property, but I couldn't.
You ternary always sets allowOutsideClick to a truthy value:
allowOutsideClick: args.allowOutsideClick ? args.allowOutsideClick : true
This needs to be changed to false if allowOutsideClick is falsy:
allowOutsideClick: args.allowOutsideClick ? args.allowOutsideClick : false
As SweetAlert accepts truthy/falsy values for its options, this can be simplified to just:
allowOutsideClick: args.allowOutsideClick
I would recommend looking at your other options and providing similar optimisations. Such as with the allowEscapeKey option (which seems to have a similar issue).
Also, anywhere that you have the pattern of:
a ? a : b
can be simplified to just
a || b
As these mean the same thing.
function show_alert(args) {
Swal.fire({
icon: args.icon,
title: args.title,
text: args.message,
html: args.html,
allowEscapeKey: args.allowEscapeKey,
allowOutsideClick: args.allowOutsideClick,
confirmButtonText: args.confirmButtonText || 'Tamam',
confirmButtonColor: args.confirmButtonColor || '#3085d6',
cancelButtonText: args.cancelButtonText || 'İptal',
cancelButtonColor: args.cancelButtonColor || '#d33',
showCancelButton: args.showCancelButton,
showCloseButton: args.showCloseButton,
showConfirmButton: args.showConfirmButton === undefined ? true : args.showConfirmButton,
didOpen: args.didOpen,
reverseButtons: true,
}).then((result) => {
if (result['isConfirmed']) {
args.callback ? args.callback_args ? args.callback(args.callback_args) : args.callback() : null;
} else if (result['isDismissed'] && args['isDismissed']) {
event.preventDefault();
args.isDismissed ? args.isDismissed() : null;
}
});
}
show_alert({
'title': 'Please wait',
'html': 'Loading audio file ...',
'allowEscapeKey': false,
'allowOutsideClick': false,
'showConfirmButton': false,
'showCancelButton': false,
'showCloseButton': false,
'didOpen': () => {
Swal.showLoading();
},
'isDismissed': () => {
console.log('dismissed');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/11.6.16/sweetalert2.min.js" integrity="sha512-4aFcnPgoxsyUPgn8gNinplVIEoeBizjYPTpmOaUbC3VZQCsRnduAOch9v0Pn30yTeoWq1rIZByAE4/Gg79VPEA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/11.6.16/sweetalert2.css" integrity="sha512-JzSVRb7c802/njMbV97pjo1wuJAE/6v9CvthGTDxiaZij/TFpPQmQPTcdXyUVucsvLtJBT6YwRb5LhVxX3pQHQ==" crossorigin="anonymous" referrerpolicy="no-referrer"/>
As a side note, you're misusing the conditional operator ? : within your .then(). You should use these when you need to use the return value that the expression evaluates to. When you don't use the evaluated value, and instead just perform side-effects, such as calling a function, then you're better off using an if-statement.
I'd also argue that only calling args.callback(args.callback_args) only when args.callback_args is truthy probably isn't what youu want to do, as this prevents you from being able to specify callback_args as falsy values such as false, 0, "", etc. You're better of always calling args.callback(args.callback_args)

jQgrid colum filtering is not working in single column

jQgrid table is workin fine. In the last line I've enabled column filtering. Search/Filtering in other column is working fine. But not working on the the Status column that has been generated from formatter
$('#jqGrid').jqGrid({
datatype: "local",
data : res.data,
colModel: [
{
label : 'Batch No.', name:'batch_no', firstsortorder:'asc'
},
{
label : 'Batch Wt.', name:'expected_batch_wt', formatter:'number', align:'right'
}
,
// ...
// ...
{
label : 'Status'
,formatter:function (cellvalue, options, rowObject){
if(condition)
status = 'MSG 1';
else if(condition)
status = 'MSG 2';
else
status = 'DEF MSG';
return status;
}
,align : 'center'
// ,sortable : false
}
],
rowNum : 1000,
rownumbers : true,
pager : '#jqGridPager',
caption : `CURRENT STOCK REPORT`,
height : '500px',
width : '1500',
footerrow : true,
userDataOnFooter : true,
gridComplete : function(){
var $grid = $('#jqGrid'),
sum_batch_count = $grid.jqGrid('getCol', 'batch_no', false, 'count'),
sum_batch_wt = $grid.jqGrid('getCol', 'expected_batch_wt', false, 'sum');
$grid.jqGrid('footerData', 'set', {
'batch_no' : sum_batch_count,
'expected_batch_wt' : sum_batch_wt
});
}
});
jQuery("#jqGrid").jqGrid('filterToolbar', { stringResult: true, searchOnEnter: false, defaultSearch: "cn" });
In your case datatype is local and the formatter shows certain value depending on condition. This value is not connected with your actual local data. When a datatype is local the search is performed within local data array - in your case this is: res.data. Since this data does not contain your new constructed values, the search return nothing.
To solve the problem one possible solution is to use unformatter function.
Depending on the jqGrid version used (Guriddo jqGrid, free-jqGrtid, jqGrid <= 4.7) you have diffrent options, but is needed to know the version. I recommend you too to search this site for solving the problem you have.

sweetalert2 text input with validation of the text with javascript in R Shiny

I am upgrading from sweetalert to sweetalert2 in R shiny and so far have managed to get the regular response by the R shiny server to ok/cancel buttons in the alert messages working, but now I am stuck with the next type, namely text input messages where I used to perform some validations for:
empty
use of special characters
before sending the value to R.
Here you can find an app in which sweetalert2 is implemented.
in the new problem I'm trying to replace the javascript in that app with a message that holds an input message:
myjava <- "shinyjs.swalFromButton = function(params) {
var defaultParams = {
title: null,
html : null
};
params = shinyjs.getParams(params, defaultParams);
swal({title : params.title, html : params.html,
input: 'text',
showCancelButton : true,
showConfirmButton : true,
closeOnConfirm: false,
confirmButtonColor: '#339FFF',
allowOutsideClick: false,
inputValidator: function(value) {
if(value === '') { return !value && 'You need to write something!'}
else {
var val2= true;
Shiny.setInputValue('option2', val2, {priority: 'event'}) };
}
});
};"
This works so far, but I have no clue how to add the other check for use of special characters (which are not allowed in file names)
In my old code I had this line for sweetalert (1) working:
var format = /[!##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/;
if(format.test(inputValue)){
swal.showInputError('Special characters are not allowed');
return false;
}
But when I build this, it doesn't work in sweetalert2:
myjava <- "shinyjs.swalFromButton = function(params) { swalFromButton = function(params) { var defaultParams = {
title: null,
html : null
};
params = shinyjs.getParams(params, defaultParams);
swal({title : params.title, html : params.html,
input: 'text',
showCancelButton : true,
showConfirmButton : true,
closeOnConfirm: false,
confirmButtonColor: '#339FFF',
allowOutsideClick: false,
inputValidator: function(value) {
if(value === '') { return !value && 'You need to write something!'}
else {
var format = /[!##$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+/;
if(format.test(value)){
return !value && 'Special characters are not allowed'}
else {
var val2= true;
Shiny.setInputValue('option2', value, {priority: 'event'})}
}
}
});
};
As promised in the other post, here is a solution without shinyjs:
library(shiny)
js <- "
Shiny.addCustomMessageHandler('sweet',
function(message) {
swal({
title : message.title,
html : message.html,
input : 'text',
showConfirmButton : true,
confirmButtonText : 'Confirm',
confirmButtonColor: '#00cc00',
showCancelButton : true,
cancelButtonText : 'Cancel',
cancelButtonColor : '#339fff',
allowOutsideClick: true,
allowEscapeKey: true,
inputValidator: function(value) {
if(value === '') {
return 'You need to write something!'
} else {
var format = /\\`|\\~|\\!|\\#|\\#|\\$|\\%|\\^|\\&|\\*|\\(|\\)|\\+|\\=|\\[|\\{|\\]|\\}|\\||\\\\|\\'|\\<|\\,|\\.|\\>|\\?|\\/|\"|\\;|\\:/g;
if(format.test(value)){
return 'Special characters are not allowed'
}
}
}
})
.then(function(result){
if(result.dismiss === swal.DismissReason.cancel) {
swal('failure');
} else {
swal('success');
Shiny.setInputValue('option1', result.value, {priority: 'event'});
}
});
}
);
"
ui <- basicPage(
tags$head(tags$script(src = "https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/7.29.2/sweetalert2.all.min.js"),
tags$link(rel="stylesheet", type="text/css", href = "https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/7.29.2/sweetalert2.min.css"),
tags$script(js)
),
actionButton("messageButton", "Click me")
)
server <- function(input, output, session){
observeEvent(input$messageButton, {
session$sendCustomMessage(type = "sweet",
message = list(title = paste('<span style ="color:#339FFF;">An alert with an input text'),
html = "Enter text"))
})
observe({print(input$option1)})
}
shinyApp(ui, server)

How to implement code mirror to show hint without CTRL+SPACE

JavaScript :
$http.get("/getApexBody", config).then(function(response) {
document.getElementById("saveBtn").disabled = false;
document.getElementById("cleanBtn").disabled = false;
$scope.apexClassWrapper = response.data;
$('#loaderImage').hide();
if (globalEditor1) {
globalEditor1.toTextArea();
}
setTimeout(function(test) {
CodeMirror.commands.autocomplete = function(cm) {
cm.showHint({
hint: CodeMirror.hint.auto
});
};
var editor = CodeMirror.fromTextArea(document.getElementById('apexBody'), {
lineNumbers: true,
matchBrackets: true,
extraKeys: {
"Ctrl-Space": "autocomplete"
},
gutters: ["CodeMirror-lint-markers"],
lint: true,
mode: "text/x-apex"
});
globalEditor1 = $('.CodeMirror')[0].CodeMirror;
}), 2000
});
This is my JS file, the ctrl-space works fine but I need, to implement autocomplete without any key bindings.
I have even tried this :
$http.get("/getApexBody", config).then(function(response) {
document.getElementById("saveBtn").disabled = false;
document.getElementById("cleanBtn").disabled = false;
$scope.apexClassWrapper = response.data;
$('#loaderImage').hide();
if (globalEditor1) {
globalEditor1.toTextArea();
}
setTimeout(function(test) {
/* CodeMirror.commands.autocomplete = function(cm) {
cm.showHint({
hint: CodeMirror.hint.auto
});
};*/
var editor = CodeMirror.fromTextArea(document.getElementById('apexBody'), {
lineNumbers: true,
matchBrackets: true,
/*extraKeys: {
"Ctrl-Space": "autocomplete"
},*/
gutters: ["CodeMirror-lint-markers"],
lint: true,
mode: "text/x-apex"
});
editor.on('inputRead', function onChange(editor, input) {
if (input.text[0] === ';' || input.text[0] === ' ') {
return;
}
CodeMirror.commands.autocomplete = function(editor) {
editor.showHint({
hint: CodeMirror.hint.auto
});
};
});
globalEditor1 = $('.CodeMirror')[0].CodeMirror;
}), 2000
});
But this is not working.
Is there something I am missing here? How can I show live completion hints with codemirror?
I have used show-hints.js , and have modified it a bit to work for "." too.
Please help.
Use this function to autocomplete codeMirror without CTRL + Space.
Set completeSingle to false in the show-hint.js
editor.on("inputRead", function(instance) {
if (instance.state.completionActive) {
return;
}
var cur = instance.getCursor();
var token = instance.getTokenAt(cur);
if (token.type && token.type != "comment") {
CodeMirror.commands.autocomplete(instance);
}
});
$http.get("/getApexBody", config).then(function(response) {
document.getElementById("saveBtn").disabled = false;
document.getElementById("cleanBtn").disabled = false;
$scope.apexClassWrapper = response.data;
$('#loaderImage').hide();
if (globalEditor1) {
globalEditor1.toTextArea();
}
setTimeout(function(test) {
/*CodeMirror.commands.autocomplete = function(cm) {
cm.showHint({
hint: CodeMirror.hint.auto
});
};*/
var editor = CodeMirror.fromTextArea(document.getElementById('apexBody'), {
lineNumbers: true,
matchBrackets: true,
styleActiveLine: true,
extraKeys: {
".": function(editor) {
setTimeout(function() {
editor.execCommand("autocomplete");
}, 100);
throw CodeMirror.Pass; // tell CodeMirror we didn't handle the key
}
},
gutters: ["CodeMirror-lint-markers"],
lint: true,
mode: "text/x-apex"
});
editor.on('inputRead', function onChange(editor, input) {
if (input.text[0] === ';' || input.text[0] === ' ') {
return;
}
//CodeMirror.commands.autocomplete = function(editor) {
editor.showHint({
hint: CodeMirror.hint.auto
});
//};
});
globalEditor1 = $('.CodeMirror')[0].CodeMirror;
}), 2000
});
This works, but after entering ".", it does gives methods of that particular variable but after entering few more matching words it again starts showing hints from original set of words.
for eg: isBatch and isAbort are two methods of System class.
When I start typing Sy... System comes up, then I type ".", them the two methods shows up isBatch and isAbort, but when I type isA instead of showing isAbort it starts showing hints from full list of words again.
Is there a way to avoid this too?

Unable to load server side data using Scroller Extension jQuery Datatable

I am trying to render my Datatable with Scroller plugin in. Data is loading once but when scrolled further shows loading data only. Am I missing something ? I am trying to implement it in Salesforce Lightning. I have loaded Scroller Library v1.4.2 and DataTable v1.10.11
sessionTable = $j('#table-1').DataTable(
{
"info": true,
"searching": true,
"processing": false,
"dom": '<"div-pg"pi><"div-search"f><"div-tbl">t<"bottom-info"> ', // f search, p :- pagination , l:- page length
paging:true,
"order" : [[2,"asc"]],
"serverSide": true,
//scrollY: "200px",
scrollX : true,
"ajax": function (data, callback, settings) {
var allRecs = component.get("c.runQuery");
allRecs.setParams(
{
"request" : data ,
});
allRecs.setCallback(this, function(response)
{
console.log('in setCallback Populating Data' );
/*console.log(response.getReturnValue());*/
var state = response.getState();
if(state === 'SUCCESS' && response.getReturnValue != null)
{
//callback(JSON.parse(response.getReturnValue()));
//callback(sessionTable.rows.add(JSON.parse(response.getReturnValue())).columns.adjust().draw());
var resp = JSON.parse(response.getReturnValue());
console.log(resp);
setTimeout( function () {
callback( {
draw:resp.draw,
data: JSON.parse(resp.data),
recordsTotal: resp.recordsTotal,
recordsFiltered: resp.recordsTotal
} );
}, 200 );
});
$A.enqueueAction(allRecs);
},
scrollY: "300px",
scroller: {
loadingIndicator: true
},
scrollCollapse: true,
"language":
{
"emptyTable": "Loading Data"
},
The issue was with Salesforce Lightning, it was not returning the response.
Here is walkaround for this, we can force Salesforce to give response by adding following code after enqueuing:-
$A.enqueueAction(allRecs);
window.setTimeout(
$A.getCallback(function() {
console.log('Calling');
}), 200);

Categories

Resources