How to get Finish button event in BPF in CRM 365? - javascript

I have created a BPF in CRM 365. In that after selecting 1 value on first stage another stage gets opened and that will be last stage. As you can see in the screenshot, I need to call javascript function on click of "Finish" button. If I get that event, I would be checking the value of Create Follow up field. If that is No, then I will do some logic henceforth.
Now my question is : How to get that Finish button event in that stage so that it goes to javascript code?
Any pointers please?

This is a working example of an entity form's JavaScript web resource,
var PUBLISHER = PUBLISHER || {};
PUBLISHER.pub_entityname = PUBLISHER.pub_entityname || (function () {
return {
onFormLoad: function (executionContext) {
var formContext = executionContext.getFormContext();
// Declare BPF OnProcessStatusChange event handler and pass in
// your own function. Execution context is passed in automatically.
formContext.data.process.addOnProcessStatusChange(BpfStatusChange);
}
};
function BpfStatusChange(executionContext) {
var formContext = executionContext.getFormContext();
var bpfStatus = formContext.data.process.getStatus();
if (bpfStatus === "finished") {
// Do something.
} else if (bpfStatus === "aborted") {
// Do something.
} else if (bpfStatus === "active") {
// Do something.
}
}
})();
The 'OnProcessStatusChange' event handler needs to be created manually in the form's 'onLoad' event. There are three BPF statuses available, when a user clicks the 'Finish' or 'Next' button, this will react if the Business Process Flow's status changes.
MS Docs

Related

Onclick & boolean switch

I have tried to make an function with a onclick that when you click it, it will change the value from 'suspended' in true (this is about suspending a website user account)
suspended = false;
type user = User['suspended'];
function blokkeerFunctie() {
// get user & user element
document.getElementById('userInfo') && document.getElementById('blokkeren');
// blocks user when clicked
if (document.getElementById('blokkeer')?.addEventListener('click', blokkeerFunctie)) {
type user = !User['suspended'];
} else {
// deblocks user when clicked
document.getElementById('deblokkeer')?.addEventListener('click', blokkeerFunctie);
type user = User['suspended'];
}
console.log('blokkeerFunctie');
}
blokkeerFunctie();
I thought with !User i will reverse the boolean value from false in true, but that code isn't even read. ▼
'user' is declared but never used.ts(6196)
You shouldn't put event listeners in your conditional if/else in this way. Here's how I would approach what you're trying to accomplish. You will need to add types to these variables, but you'll get the basic logic here.
let User = {
suspended: true
};
let button = document.querySelector('#suspender');
function setSuspendButton() {
button.innerText = User['suspended'] ? 'Unsuspend' : 'Suspend';
}
window.addEventListener('load', () => {
button.addEventListener('click', blokkeerFunctie)
setSuspendButton();
})
function blokkeerFunctie() {
User['suspended'] = !User['suspended'];
setSuspendButton();
}
<button id='suspender'></button>
type user = creates a new type, not a value. It's unused in each branch of the if because you just create a new type, named user which shadows the type of the same name from the parent scope, which is never used by anything.
Furthermore, this line does nothing:
document.getElementById('userInfo') && document.getElementById('blokkeren');
This line gets up to two references to DOM elements, but doesn't save them anywhere, or perform any logic on them.
I think you want something more like this?
const user = {
name: 'Joe',
suspended: false
}
function blokkeerFunctie() {
// block/deblocks user when clicked
if (document.getElementById('blokkeer')?.addEventListener('click', blokkeerFunctie)) {
user.suspended = !user.suspended // toggle `suspended` back and forth
}
console.log('blokkeerFunctie');
}
blokkeerFunctie();
Working example

Multiple functions on one event not working

So the logic behind my question:
I have a list like this:
<ul>
<li>
Edit
</li>
<li>
Edit
</li>
<li>
Edit
</li>
</ul>
So when I press Edit link, I must collect data-kms and data-date by using this function, and put them into localStorage:
function setCurrent() {
//Set localStorage items for clicked element
localStorage.setItem('currentKms', $(this).data('kms'));
localStorage.setItem('currentDate', $(this).data('date'));
//Get data
var kms = localStorage.getItem('currentKms');
var date = localStorage.getItem('currentDate');
//Insert data into edit form
$('#editKms').val(kms);
$('#editDate').val(date);
}
And then I want to delete that entry from local storage using this function:
function deleteRun() {
//Get Current Data
var currentKms = localStorage.getItem('currentKms');
var currentDate = localStorage.getItem('currentDate');
var runs = getRunsObject();
var i = 0;
//Loop throuh runs and remove current run from 'runs' object
while (i < runs.length) {
//Remove Current Run
if (runs[i].kms == currentKms && runs[i].date == currentDate) {
runs.splice(i, 1);
alert('Run Deleted');
} else {
alert('Run cant be deleted!');
}
//Save array without current run
localStorage.setItem('runs', JSON.stringify(runs));
i++;
}
//Show Runs Again
$('.original').hide();
showRuns();
//Preventing form from submiting
return false;
}
So basically I have to run 2 functions on 1 event at the same time.
And I'm trying to do it like this:
$('.deleteLink').on('tap', function(){
setCurrent();
deleteRun();
});
But for some reason setCurrent doesn't save the data as it supposed to, it sets values to undefined instead.
But if I run it like this:
$('.deleteLink').on('tap', setCurrent);
It works fine, and it's actually setting correct values to currentKms & currentDate.
So how do I correctly run both of this functions on same event? Because
function(){
setCurrent();
deleteRun();
});
isn't working in my case for some reason.
As per your approach this in the function setCurrent doesn't refers to the element which invoked the event.
You can use .call()
The call() method calls a function with a given this value and arguments provided individually.
$('.deleteLink').on('tap', function(){
setCurrent.call(this);
deleteRun();
});
You can use bind()
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
Code
$('.deleteLink').on('tap', function(){
setCurrent.bind(this)();
deleteRun();
});

How do I remove YUI delegated events?

I'm attempting to create a script for a platform that allows users to inject javascript. They are using YUI and specifically Y.one('body).delegate('click',...) to attach an event to a button. I would like to intercept this button but I cannot figure out how to stop, block, remove or otherwise prevent the event handler from firing.
Note: I don't have direct access to the handler returned by `Y.delegate()
So far I've tried
Y.detachAll('click');
Y.unsubscribeAll('click');
Y.one('body').detachAll('click');
Y.one('body').unsubscribeAll('click');
Y.one('.the-delegated-class').detachAll('click');
Y.one('.the-delegated-class').unsubscribeAll('click');
All to no avail. In fact the only success I've had is to completely remove and replace the body HTML which obviously takes all the event handlers with it as opposed to just the one I want to remove.
Any insights?
Turns out one of my attempts was the correct method but my usage was wrong. I was (unknowingly) attempting to detach the event prior to it being attached in the first place.
That said in the case of:
Y.one('body).delegate('click',...)
This works:
Y.one('body').detach('click')
Though ideally you'd call detach direct on the EventHandle returned by the delegate call.
The delegate Event method does not appear to store the handles anywhere, you could potentially create a patch replacement for Event.delegate that stores the handles against the delegate element. A basic example of patching YUI: https://gist.github.com/tivac/1424351
Untested code:
var config = {
groups : {
patches : {
base : "/js/patches/",
modules : {
"node-event-delegate-patches" : {
path : "node-event-delegate.js",
condition : {
name : "node-event-delegate-patches",
trigger : "node-event-delegate",
test : function() { return true; }
}
}
}
}
}
};
YUI.add("node-event-delegate-patches", function(Y) {
var L = Y.Lang;
Y.Node.prototype.delegate = function(type) {
var args = Y.Array(arguments, 0, true),
handle,
index = (L.isObject(type) && !L.isArray(type)) ? 1 : 2;
args.splice(index, 0, this._node);
if (!L.isArray(this._node._delegate_event_handles)){
this._node._delegate_event_handles = [];
}
handle = Y.delegate.apply(Y, args);
this._node._delegate_event_handles.push( handle );
return handle;
};
Y.Node.prototype.detachDelegates = function(){
Y.Array.each(this._node._delegate_event_handles, function(handle){
handle.detach();
});
}
});

Javascript order of execution: how to detect object creation

I want to instantiate a new MediaElementPlayer object. When it's successfully created, I want to pass the whole object on to another function (my_object.attachEvents). My code is as follows:
var options = {
success: function () {
//point 2
console.log("passing player object", local_player_instance);
my_main_object.attachEvents(local_player_instance);
}
}
//point 1
console.log('player inited', local_player_instance);
local_player_instance.video = new MediaElementPlayer('#video_player', options);
my_main_object.attachEvents = function(local_player_instance) {
local_player_instance.video.play()
}
In Firefox, the assignment at point one is executed before the line at point 2 calls the attach events method.
Im Chrome, point 2 is evaluate first, and as a result when the play method in the attach events function is called it doesn't exist.
My question is, how do I pass successfully pass the MediaElementPlayer to another function when it is created?
The best way to handle this in a cross browser way is
// here's where you'll store a global reference to the player
var globalMediaElement = null;
var options = {
success: function (domNode, mediaElement) {
globalMediaElement = mediaElement;
doStuff();
// you can also get the the player via jQuery here
$('#video_player').player
}
}
// create MediaElement
new MediaElementPlayer('#video_player', options);
function doStuff() {
globalMediaElement.play();
}

Javascript object methods and binding functions

I'm looking for some help because I don't quite think I understand the Javascript scoping rules. What I'm trying to do in the below example is to push a button on a page that then starts listening for keyboard input. Once the keyboard input has started if there is a break in input for two seconds I want to stop capturing the input and pop an alert with the full contents of the input collected to that point. This is an example I made purely for this question.
What I see is that I click the button and start entering input. On each keypress I am alerted to the string collected to that point. After the two second, no-action timeout takes place I see an alert with the contents "undefined". The first alerts listed above come from startLog(). The second alert comes from stopLog(). What am I doing wrong when I call stopLog that it is telling me that this.message is undefined?
function Logger() {
this.message = '';
this.listenTimer;
this.startLog = function() {
this.message = '';
$(document).bind('keypress', {this_obj:this}, function(event) {
event.preventDefault();
var data = event.data;
clearTimeout(data.this_obj.listenTimer);
data.this_obj.message += String.fromCharCode(event.which);
alert(data.this_obj.message);
data.this_obj.listenTimer = setTimeout(data.this_obj.stopLog, 2000);
});
};
this.stopLog = function() {
$(document).unbind("keypress");
alert(this.message);
};
}
var k = new Logger();
$('.logging-button').click(function() {
k.startLog();
});
The issue is this. When you pass an object method as an event handler, it loses its object context; this will refer to the window object.
There are various ways to fix this, but the main issue is that you need to pass setTimeout a closure that will still refer to the correct context:
setTimeout(function() { data.this_obj.stopLog() }, 2000);
On a separate note, you can save yourself some unnecessary code by just using a closure to refer to the object, rather than binding it as event.data:
this.startLog = function() {
this.message = '';
var this_obj = this;
$(document).bind('keypress', function(event) {
event.preventDefault();
clearTimeout(this_obj.listenTimer);
// etc
});
};
var k = new Logger();
$('.logging-button').click(function() {
k.startLog.apply(this);
//Setting context of "this" so that it refers to element even in startLog()
});

Categories