JavaScript to confirm before BPF movement not working in Dynamics 365 CRM - javascript

I need help on the below JavaScript; everything is working fine except when the user selects the next stage, Confirm Dialog prompt for confirmation, but when the user clicks on the OK button in the dialog box, this action does not move to the next stage. Simply close the dialog box. If anyone can help me with this?
function onLoad(executionContext) {
var formContext = executionContext.getFormContext();
var process = formContext.data.process;
//handles changes to the BPF before they actually occur
process.addOnPreStageChange(myProcessStateOnPreChange);} function myProcessStateOnPreChange(executionContext) {
var formContext = executionContext.getFormContext();
var process = formContext.data.process;
var eventArgs = executionContext.getEventArgs();
var currentStageId = process.getActiveStage().getId();
var nextStageId = process.getSelectedStage().getId();
//dont allow to go back using the set active button
if (currentStageId != nextStageId) {
eventArgs.preventDefault();
Xrm.Utility.alertDialog("You cannot set completed stage as Active.")
return;
}
if (eventArgs._direction === 1) //backwards
{
//logic based upon the BPF going to the previous Stage.
eventArgs.preventDefault();
var alertStrings = { cancelButtonLabel: "Cancel", confirmButtonLabel: "OK", text: "Backward stage movement is not allowed", title: "Warning" };
var alertOptions = { height: 120, width: 260 };
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions);
return;
}
//otherwise forward
// logic based upon the BPF going to the next Stage.
if (eventArgs._direction === -1)
{ eventArgs.preventDefault();
var confirmStrings = {
cancelButtonLabel: "Cancel",
confirmButtonLabel: "OK",
text: "Are you sure you want to move forward in the BPF?",
title: "Confirm BPF Movement"
};
var confirmOptions = { height: 120, width: 260 };
Xrm.Navigation.openConfirmDialog(confirmStrings, confirmOptions).then(function(success) {
if (success.confirmed) {
formContext.data.process.moveNext();
console.log("BPF movement confirmed");
} else
{
console.log("BPF movement cancelled");
}
});
}
//Xrm.Utility.alertDialog("Warning: You cannot undo this movement.")}
BPF in Dynamics 365 CRM is supposed to move to the next stage after confirming the dialog prompt and the user clicks on the OK button

Related

Undefined blot inserted after embedding custom inline blot in Quill editor

I am working on twitter like user mentions for Quill editor.
My custom blot code is
import Quill from 'quill';
const Base = Quill.import('blots/inline');
export default class MentionBlot extends Base {
static create(data) {
const node = super.create(data.name);
node.innerHTML = `#${data.name}`;
node.setAttribute('contenteditable', false);
node.setAttribute('name', data.name);
node.setAttribute('id', data.id);
return node;
}
MentionBlot.blotName = 'usermention';
MentionBlot.tagName = 'aumention';
I am displaying users list in dropdown. When ever one of the user name is clicked, I am embedding the user as #User in quill editor.
this is the click event I had written for it. The thing I am doing here is I am replacing the text user entered after # with the custom Inline blot.
searchResult.forEach(element => {
element.addEventListener('click', e => {
e.preventDefault();
e.stopPropagation();
const quillEditor = window.editor;
const content = quillEditor.getText();
const quillRange = quillEditor.selection.savedRange; // cursor position
if (!quillRange || quillRange.length != 0) return;
const cursorPosition = quillRange.index;
let mentionStartAt = 0;
let lengthToBeDeleted = 0;
for (let i = cursorPosition - 1; i >= 0; --i) {
const char = content[i];
if (char == '#') {
mentionStartAt = i;
lengthToBeDeleted += 1;
break;
} else {
lengthToBeDeleted += 1;
}
}
const data = {
name: element.innerHTML,
id: element.getAttribute('id')
};
quillEditor.deleteText(mentionStartAt, lengthToBeDeleted);
quillEditor.insertEmbed(mentionStartAt, 'usermention', data, 'api');
const cursorAfterDelete =
quillEditor.selection.savedRange.index + element.innerHTML.length;
quillEditor.insertText(cursorAfterDelete + 1, ' ', 'api');
quillEditor.setSelection(cursorAfterDelete + 2, 'api');
quillEditor.format('usermention', false, 'api');
});
});
}
Until here, everything is working like charm but the issue I am facing is after inserting the embed usermention blot, If the user enters Enter button on Keyboard to go to new line, Quill's handleEnter() function is getting triggered and it is inserting #undefined usermention blot to the editor.
After executing the above function, my editor state is this.
When I press enter to go to new line, this is the debug state of handleEnter() function - Quill
#undefined usermention got inserted into the editor. I want the user to enter new line.
When the user presses Enter, I understood that quill.format() is returning usermention:true. But if the user presses Enter after typing few more characters, it is taking him to new line and in this case quill.format() is empty.
Can some one please help me in this regard. Thank you.
Reference: https://quilljs.com/docs/modules/keyboard/
Handling enter with Quill keyboard binding is easier than adding addLister to it, the below method helps you to handle whenever the enter event fires in the quill editor
var quill = new Quill('#editor', modules: {
keyboard: {
bindings: bindings
}}});
var bindings = {
handleEnter: {
key: '13', // enter keycode
handler: function(range, context) {
//You can get the context here
}
}
};
I hope the above answer suits your needs.

Why doesn't my if statement return the expected result?

I'm trying to make a Catchphrase style game where the user gradually clicks squares covering a picture until they can guess the person in the picture. The relevant code and comments are below:
// One of three random images to be displayed when page refreshes.
var randomImage = new Array();
randomImage[0] = "/IMAGES/0.jpg"
randomImage[1] = "/IMAGES/1.jpg"
randomImage[2] = "/IMAGES/2.jpg"
var randomNumber = Math.random();
randomNumber = randomNumber * randomImage.length;
randomNumber = Math.round(randomNumber);
if (randomNumber == 0) {
document.getElementById("backPic").src="../IMAGES/0.jpg";
}
else if (randomNumber == 1) {
document.getElementById("backPic").src="../IMAGES/1.jpg";
}
else {
document.getElementById("backPic").src="../IMAGES/2.jpg";
}
// When user submits their answer, if they are correct, they are alerted 'Well done!'
document.getElementById("submitGuess").onclick = function() {
var correctAnswer0 = "Terry";
var correctAnswer1 = "Drogba";
var correctAnswer2 = "Lampard";
if (document.getElementById("userGuess").value == correctAnswer1 && randomNumber == 1){
alert("Well done!");
}
}
In the if statement above, I expect that only when submit is clicked, and userGuess is correct and randomNumber is equal to 1, that the user is alerted 'Well done'. However when the submit button is clicked when a different picture is displayed (i.e. randomImage[2]), it instead changes the picture to randomImage[1].
Can anyone help me and tell me why this isn't working?
Thank you!
The button submits the form and so the page gets reloaded. To avoid this, add the event parameter to your click handler function (e.g. name it e) and do:
e.preventDefault();
This will cancel the form submission and thus not reload the page.
Note that your code can be reduced a lot, by using a better data structure:
// One of three random images to be displayed when page refreshes.
var persons = [
{name: "Terry", img: "https://upload.wikimedia.org/wikipedia/commons/f/f8/John_Terry_during_a_match_vs_Everton_at_Stamford_Bridge_in_2006.jpg"},
{name: "Drogba", img: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/89/Didier_Drogba_9248.JPG/399px-Didier_Drogba_9248.JPG"},
{name: "Lampard", img: "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b3/Frank_Lampard%2713-14.JPG/399px-Frank_Lampard%2713-14.JPG"}
];
var randomNumber = Math.floor(Math.random() * persons.length);
backPic.src = persons[randomNumber].img;
// When user submits their answer, if they are correct, they are alerted 'Well done!'
submitGuess.addEventListener("click", function(e) {
alert(userGuess.value == persons[randomNumber].name
? "Well done!"
: "Try again"
);
e.preventDefault(); // cancel form submission.
});
<form>
<img id="backPic" width="20%" height="20%"><br>
Guess:<input id="userGuess">
<button id="submitGuess">Guess</button>
</form>

zone.js: 140 Uncaught TypeError: Cannot read property 'remove'

I am new to kendo ui.
I developed prototype in my fiddle. delete confirmation window is working fine there.
but when I integrate in my codebase I am getting error Cannot read property 'remove' at the line pai_to_delete.remove();
can you guys tell me how to fix it.
providing my code below.
updated
-may be I did not explain you properly...how my ui looks is when I click a link a big popup opens with a grid...in that grid when i click a column
a small popup with delete option opens up...when I click the delete option a confirmation window opens...
- when I use native js confirm method it works fine..I think that time its referring correctly...
- but when I use kendo ui popup it does not work fine...
- is my pai_to_delete not referring properly when I use kendo ui...since its referring to that div not the parent div i think so.
prototype fiddle
http://jsfiddle.net/amu6tw2a/
whole code I am not able to paste in my question so I am pasting in fiddle, relevant code I am pasting below
https://jsfiddle.net/44tLx225/
zone.js: 140 Uncaught TypeError: Cannot read property 'remove'
of null
at HTMLButtonElement.eval(swimming - jumpings.ts: 990)
at HTMLDocument.dispatch(jquery - 2.2.3. js: 4737)
at HTMLDocument.elemData.handle(jquery - 2.2.3. js: 4549)
at ZoneDelegate.invokeTask(zone.js: 236)
at Zone.runTask(zone.js: 136)
at HTMLDocument.ZoneTask.invoke(zone.js: 304)
$(".tiger").bind("click", function(e) {
let that = this;
$(".pai-del-menu").blur(function() {
$(this).hide();
pai_to_delete = null;
});
$(".pai-del-menu").click(function() {
$(this).hide();
//let popup = $("#deletePopup").data("kendoWindow").center().open();
if (pai_to_delete != null) {
//$('.addELFDocumentForm').show();
//alert("Are you sure you want to delete the selected jumping");
var kendoWindow = $("<div />").kendoWindow({
title: "Confirm",
resizable: false,
modal: true,
height: 100,
width: 400
});
kendoWindow.data("kendoWindow")
.content($("#delete-confirmation").html())
.center().open();
$(jumping).on("click", "#playerDocumentOk", function() {
pai_to_delete.remove();
kendoWindow.data("kendoWindow").close();
})
$(jumping).on("click", "#playerDocumentCancel", function() {
kendoWindow.data("kendoWindow").close();
})
//pai_to_delete.remove();
}
});
var record_x = e.pageX;
var record_y = e.pageY - $(".navHeaderBox").height() - $(".breadCrumbBox").height() - 20;
$(".pai-del-menu").css({
left: record_x,
top: record_y
});
$(".pai-del-menu").fadeIn(200);
$(".pai-del-menu").show();
$(".pai-del-menu").attr('tabindex', -1).focus();
pai_to_delete = $(this).parent().parent();
});
works with js native confirm method
$(".tiger").bind("click", function(e) {
$(".pai-del-menu").blur(function() {
$(this).hide();
pai_to_delete = null;
});
$(".pai-del-menu").click(function() {
$(this).hide();
if (pai_to_delete !== null) {
//alert("Are you sure you want to delete the selected document");
//confirm("Are you sure you want to delete the selected document");
var r = confirm("Are you sure you want to delete the selected document");
if (r == true) {
//txt = "You pressed OK!";
pai_to_delete.remove();
} else {
//txt = "You pressed Cancel!";
}
//pai_to_delete.remove();
}
});
var pai_x = e.pageX;
var pai_y = e.pageY - $(".navHeaderBox").height() - $(".breadCrumbBox").height() - 20;
$(".pai-del-menu").css({
left: pai_x,
top: pai_y
});
$(".pai-del-menu").fadeIn(200);
$(".pai-del-menu").show();
$(".pai-del-menu").attr('tabindex', -1).focus();
pai_to_delete = $(this).parent().parent();
});
The key difference between native confirm method and custom modal window - native confirm method is synchronous.
When method is synchronous and you clicks Ok/Cancel in native confirm dialog, $(".pai-del-menu").blur even occurs, but executes only after $(".pai-del-menu").click was finished, so everything works fine.
When method is asynchronous and you clicks Ok/Cancel on modal window, $(".pai-del-menu").blur even occurs and executes immediately, removing pai_to_delete reference, so inside $(".pai-del-menu").click event pai_to_delete is already null.
All you need is to assign pai_to_delete to another variable right before kendoWindow creation and use it inside $(".pai-del-menu").click event:
$(".pai-del-menu").blur(function() {
$(this).hide();
pai_to_delete = null;
});
$(".pai-del-menu").click(function() {
$(this).hide();
if (pai_to_delete != null) {
var paiToDelete = pai_to_delete; // <----
var kendoWindow = $("<div />").kendoWindow({
title: "Confirm",
resizable: false,
modal: true,
height: 100,
width: 400
});
kendoWindow.data("kendoWindow")
.content($("#delete-confirmation").html())
.center().open();
$(jumping).on("click", "#playerDocumentOk", function() {
paiToDelete.remove(); // <----
kendoWindow.data("kendoWindow").close();
});
$(jumping).on("click", "#playerDocumentCancel", function() {
kendoWindow.data("kendoWindow").close();
});
}
});

How to show confirmation pop up when changing page in DataTable

I am landing on the first page of DataTable, make some changes.
Then I move to the second page.
Actually, confirmation popup is shown but it navigate to the second page.
Expected: confirm pop is shown but it still landing on the first.
Here is my code:
$('#dataTable-id').on( 'page.dt', function (event) {
if( change ){
bootbox.dialog({
title: "Confirmation",
message : "Discard changes?",
buttons :{
main: {
label : "Leave",
className : "btn-primary",
callback: function (){
// To avoid broking page/length controller
// move to other pages
return true; // cancel draw
}
},
cancel: {
label : "Stay",
className : "btn-default",
callback : function() {
// stay at current page.
return true;
}
}
},onEscape: function () {return true;}
});
}
});
How to show confirmation popup before page change?
The page.dt event is only informational, it can not be canceled.
You can workaround that restriction by writing a custom preDrawCallback like discussed here: https://datatables.net/forums/discussion/25507
EDIT: You have to cancel the redraw generally and do the paging manually in the bootbox callback (as it does not work as a real modal dialog like the native javascript confirm()). I modified the above example to incorporate a bootbox confirm dialog on paging: https://jsfiddle.net/bk4nvds5/
$(document).ready(function () {
var pageLen = 10;
var originalPage = 0;
var originalPageLen = pageLen;
var gotoPage = 0;
var gotoPageLen = originalPageLen;
var fromBootbox = false;
var table = $('#example').DataTable({
"pageLength": pageLen,
"preDrawCallback": function (settings) {
if(table){ // ignore first draw
if (!fromBootbox) {
// To avoid broking page/length controller, we have to reset the paging information
gotoPage = settings._iDisplayStart;
gotoPageLen = settings._iDisplayLength;
bootbox.confirm("Are you sure?", function(result) {
console.log("goto page" + gotoPage + " (result: " + result + ")");
if (result) {
fromBootbox = true;
table.page.len(gotoPageLen);
table.page(gotoPage / gotoPageLen).draw(false);
fromBootbox = false;
}
});
settings._iDisplayStart = originalPage;
settings._iDisplayLength = originalPageLen;
$('[name="example_length"]').val(originalPageLen);
return false; // cancel draw
}else{
originalPage = settings._iDisplayStart;
originalPageLen = settings._iDisplayLength;
}
}
}
});
});

AngularJS How to restrict double/multiple click

I know a solution for double/multi click on angularJS that disable on button click & enable it after completing ajax processing using ng-disabled. Please suggest any other best solution for handling double click in angularJS...
Our code will call ajax method on button click & will take small amount of tme to process & get data from db. We have to restrict second/ multi clicks mean while.
I don't want to allow click when ajax in progress...
Welcome Please be simple solutions rather than using ng-disabled, I am learner of AngularJS
createDialogService('ajs/common/templates/popup/config_reminder_popup.html',
{
title: isFrom,
backdrop: true,
controller: 'configRemindersCBController',
footerTemplate: '' + action + ''
});
$scope.saveOrUpdateReminder = function (reminder)
{
if ($scope.isDisabled)
{
return;
}
$scope.isDisabled = true;
if (!reminder.daysBeforeAfterCheckDate || reminder.daysBeforeAfterCheckDate === '')
{
alertService.openValidatPopup('Please enter days before expiration.', "Error", true, 'configRemindersCBController', 'Ok', 'u1_remove.png');
$scope.isDisabled = false;
return;
}
configRemindersService.isDaysBeforeAfterCheckDate($scope.objectId, reminder, function (result)
{
if (!reminder.selectedMessageTemplate.messageId || reminder.selectedMessageTemplate.messageId === '')
{
alertService.openValidatPopup('Please select message template.', "Error", true, 'configRemindersCBController', 'Ok', 'u1_remove.png');
$scope.isDisabled = false;
return;
}
else if (!reminder.selectedReminderSendOption.reminderSendOptionValue || reminder.selectedReminderSendOption.reminderSendOptionValue === '')
{
alertService.openValidatPopup('Please select reminder send option.', "Error", true, 'configRemindersCBController', 'Ok', 'u1_remove.png');
$scope.isDisabled = false;
return;
}
var enableReminder;
if (result.Result === 'No')
{
if (reminder.enable === true)
{
enableReminder = 'Enable';
}
else
{
enableReminder = 'Disable';
}
configRemindersService.addOrUpdateReminderConfigLine($scope.objectId, reminder, enableReminder, function (remindersResponse)
{
var reminder = remindersResponse.reminderConfigLine;
$rootScope.CONFIG = JSON.parse(remindersResponse.configData);
$scope.$modalClose();
$scope.isDisabled = false;
_.filter(configRemindersService.getMessageTemplates(), function (msg)
{
if (reminder.messageTemplateId === msg.messageId)
{
reminder.selectedMessageTemplate = msg;
}
});
_.filter(configRemindersService.getReminderSendOptions(), function (option)
{
if (reminder.reminderSendOption === option.reminderSendOptionValue)
{
reminder.selectedReminderSendOption = option;
}
});
if (configRemindersService.getIsFrom() === 'Create Reminder')
{
configRemindersService.getReminders().push(reminder);
}
else
{
configRemindersService.getReminders()[configRemindersService.getIndex()] = reminder;
}
});
}
});
};
ng-disabled is definitely the proper way to go with this -- it's a ready-made directive for disabling an object under certain conditions.
If you need to disable it without it looking disabled, you have 2 options:
Change the css for the disabled state to look like it's enabled.
Mimic this with a scope variable that only performs the actions when set.
For the second:
$scope.stopClick = false;
$scope.buttonClick = function () {
if ($scope.stopClick) { return; }
$scope.stopClick = true;
<.. code ..>
callback: function(data) {
$scope.stopClick = false;
}
};
This will accomplish the goal, but it's reinventing the wheel and is likely less robust than just disabling the element and restyling it.
Well you could do something like this :
Create a $scope variable
$scope.myFunnyPromise = null;
in the template :
<button ng-if="myFunnyPromise == null"></button>
Only show the button if myFunnyPromise equals null.
And in your function :
if($scope.myFunnyPromise !== null){
return $scope.myFunnyPromise;
}
$scope.myFunnyPromise = asyncTask().finally(function cleanUp(){
//clear the $scope variable
$scope.myFunnyPromise = null;
})
You can have a function in $rootScope which contains information about whether there is an ongoing http request. Then you can use that value to disable the buttons that you don't want successive click events.
I usually use fieldset attribute to disable input fields while there is an ongoing http request.
<fieldset ng-disabled="isWaitingForServerResponse()"> //when there is an ongoing request, input fields under this tag will be disabled </fieldset>
For implementing isWaitingForServerResponse I got help from a busy bar implementation, which shows a loading bar while there is a http request. It creates events when there is a new request and another request when it stops. So in these events I incremented a counter which holds the number of active http requests and decrement it for each http response. I haven't used it before but I guess you can also use the $http.pendingRequests property too for understanding whether there is a pending http request.
$rootScope.numberOfResponseWaitingFromServer = 0;
$rootScope.$on("cfpLoadingBar:loading", function (event) {
$rootScope.numberOfResponseWaitingFromServer++;
});
$rootScope.$on("cfpLoadingBar:loaded", function (event) {
$rootScope.numberOfResponseWaitingFromServer--;
});
$rootScope.isWaitingForServerResponse = function () {
return $rootScope.numberOfResponseWaitingFromServer > 0;
}

Categories

Resources