Prototype | keyup Event.stopObserving() not working when handler is bound to class - class

Here's my beef: I'm observing the document for a keyup and then calling a handler. The handler is calling a function of a class and is bound to the class's context. When the function is called and my conditionals are met, it's supposed to stop observing the handler. But its not.
Created a class, this is the function I'm calling on page:
look_for: function(key_combo) {
this.keys_array = key_combo.split("+");
this.match_key_handler = this.match_keys.bind(this);
document.observe('keyup', this.match_key_handler);
},
This calls the document to observe keyup and calls this.match_keys(). As you can see, it's assigned to a handler because the function needs to be bound. Below is the match_keys functions:
match_keys: function() {
// matching the keys here, blah blah
if(this.keys_matched) {
document.stopObserving('keyup',this.match_key_handler);
}
}
However, when the conditional is met, it doesn't stop observing! If I stopObserving all keyups on the document, it will unregister this function but I want it to only unregister the match_key_handler.
StackOverflow, help me out! Below is another post thats similar. Followed what was on the page but still no dice.
Stop Observing Events with JS Prototype not working with .bind(this)

Related

Event parameter overwritten after another event?

In view:
<List selectionChange=".onSelectionChange">
In controller:
onSelectionChange: function (oEvent) {
console.log(oEvent.sId); // log 1, output "selectionChange"
MessageBox.warning(Utils.i18n("CHANGE_CONFIRM"), {
actions: [ Utils.i18n("LEAVE_BTN"), MessageBox.Action.CANCEL ],
onClose: function (sAction) {
console.log(oEvent.sId); // log 2, output "closed"
if (sAction === Utils.i18n("LEAVE_BTN")) {
this._showDetail(oEvent.getParameter("listItem") || oEvent.getSource(), oEvent.getSource().data("target"));
}
}.bind(this)
});
}
Hi, may I ask why oEvent changed when onClose is triggered? Why can't I store oEvent in my scope?
Event is a module that implements Poolable, meaning that Event has to implement init and reset which will then be leveraged by its corresponding ObjectPool instance ("oEventPool" internally) to reuse the existing Event instance for the next event.
The "next event", in our case, is the "close" event which was fired by the dialog. As you could already observe, oEvent suddenly doesn't have the ID "selectionChange" but "close". This is because the Event instance was reset and reused again. And since oEvent is just a reference (not a copy), and because JS applies Call by Object-Sharing, it's "changed".
The API Reference of ObjectPool explains what it's doing with the Event instance:
(ObjectPool) maintains a list of free objects of the given type. If sap.ui.base.ObjectPool.prototype.borrowObject is called, an existing free object is taken from the pool and the init method is called on this object.
When no longer needed, any borrowed object should be returned to the pool by calling #returnObject. At that point in time, the reset method is called on the object and the object is added to the list of free objects.
Currently, the (oEvent) object is considered "no longer needed" when its handler is called. So the object is already reset right after onSelectionChange, and initialized again right before onClose is triggered.
UI5 does this so that it doesn't have to create and destroy multiple Event instances to improve performance. This is a practice borrowed from the Object Pool Design Pattern (which is also often used in game development).
So, what does it mean for us as application developers? Just don't rely on the event object that is inside a closure. Instead, assign primitive values from the object to separate variables so that we can use them later. E.g.:
onSelectionChange: function(oEvent) {
const eventId = oEvent.getId(); // === "selectionChange"
MessageBox.warning(/*...*/, {
onClose: function() {
/* oEvent.getId() === suddenly "close" but
eventId === still "selectionChange" 👍 */
},
});
},

Get newly created id of a record before redirecting page

I would like to retrieve the id of a newly created record using javascript when I click on save button and just before redirecting page.
Do you have any idea please ?
Thank you !
One way to do this in Sugar 7 would be by overriding the CreateView.
Here an example of a CustomCreateView that outputs the new id in an alert-message after a new Account was successfully created, but before Sugar gets to react to the created record.
custom/modules/Accounts/clients/base/views/create/create.js:
({
extendsFrom: 'CreateView',
// This initialize function override does nothing except log to console,
// so that you can see that your custom view has been loaded.
// You can remove this function entirely. Sugar will default to CreateView's initialize then.
initialize: function(options) {
this._super('initialize', [options]);
console.log('Custom create view initialized.');
},
// saveModel is the function used to save the new record, let's override it.
// Parameters 'success' and 'error' are functions/callbacks.
// (based on clients/base/views/create/create.js)
saveModel: function(success, error) {
// Let's inject our own code into the success callback.
var custom_success = function() {
// Execute our custom code and forward all callback arguments, in case you want to use them.
this.customCodeOnCreate(arguments)
// Execute the original callback (which will show the message and redirect etc.)
success(arguments);
};
// Make sure that the "this" variable will be set to _this_ view when our custom function is called via callback.
custom_success = _.bind(custom_success , this);
// Let's call the original saveModel with our custom callback.
this._super('saveModel', [custom_success, error]);
},
// our custom code
customCodeOnCreate: function() {
console.log('customCodeOnCreate() called with these arguments:', arguments);
// Retrieve the id of the model.
var new_id = this.model.get('id');
// do something with id
if (!_.isEmpty(new_id)) {
alert('new id: ' + new_id);
}
}
})
I tested this with the Accounts module of Sugar 7.7.2.1, but it should be possible to implement this for all other sidecar modules within Sugar.
However, this will not work for modules in backward-compatibility mode (those with #bwc in their URL).
Note: If the module in question already has its own Base<ModuleName>CreateView, you probably should extend from <ModuleName>CreateView (no Base) instead of from the default CreateView.
Be aware that this code has a small chance of breaking during Sugar upgrades, e.g. if the default CreateView code receives changes in the saveModel function definition.
Also, if you want to do some further reading on extending views, there is an SugarCRM dev blog post about this topic: https://developer.sugarcrm.com/2014/05/28/extending-view-javascript-in-sugarcrm-7/
I resolved this by using logic hook (after save), for your information, I am using Sugar 6.5 no matter the version of suitecrm.
Thank you !

event callback argument is empty

I've got event listeners defined as <AgGridReact> properties and then also just added this to my onGridReady callback:
grid.api.addEventListener('sortChanged',
evt => {
console.log(evt);
debugger;
});
Either way, the evt object is empty (an empty object, not undefined). Is this expected behavior or am I doing something wrong? The documentation (https://www.ag-grid.com/javascript-grid-events/) doesn't say anything about what to expect.
What you have is fine, but all 3 of the "sort" events:
sortChanged
beforeSortChanged
afterSortChanged
are notification only events - no event object are passed into the event itself

D: Delegates or callbacks?

I found conception of Delegates pretty hard for me. I really do not understand why I can't simply pass one function to another and need to wrap it to Delegate. I read in docs that there is some cases when I do not know it's name and Delegate is only way to call it.
But now I have trouble in understanding conception of callbacks. I tried to find more information, but I can't understand is it's simply call of other function or what is it.
Could you show examples of D callbacks and explain where they can be helpful?
import vibe.d;
shared static this()
{
auto settings = new HTTPServerSettings;
settings.port = 8080;
listenHTTP(settings, &handleRequest);
}
void handleRequest(HTTPServerRequest req,
HTTPServerResponse res)
{
if (req.path == "/")
res.writeBody("Hello, World!", "text/plain");
}
&handleRequest is it callback? How it's work and at what moment it's start?
So within memory a function is just a pile of bytes. Like an array, you can take a pointer to it. This is a function pointer. It has a type of RETT function(ARGST) in D. Where RETT is the return type and ARGST are the argument types. Of course attributes can be applied like any function declaration.
Now delegates are a function pointer with a context pointer. A context pointer can be anything from a single integer (argument), call frame (function inside of another) or lastly a class/struct.
A delegate is very similar to a function pointer type at RETT delegate(ARGST). They are not interchangeable, but you can turn a function pointer into a delegate pointer pretty easily.
The concept of a callback is to say, hey I know you will know about X so when that happens please tell me about X by calling this function/delegate.
To answer your question about &handleRequest, yes it is a callback.
You can pass functions to other functions to later be called.
void test(){}
void receiver(void function() fn){
// call it like a normal function with 'fn()'
// or pass it around, save it, or ignore it
}
// main
receiver(&test); // 'test' will be available as 'fn' in 'receiver'
You need to prepend the function name as argument with & to clarify you want to pass a function pointer. If you don't do that, it will instead call that function due to UFCS (calling without braces). It is not a delegate yet.
The function that receives your callable may do whatever it wants with it. A common example is in your question, a web service callback. First you tell the framework what should be done in case a request is received (by defining actions in a function and making that function available for the framework), and in your example enter a loop with listenHTTP which calls your code when it receives a request. If you want to read more on this topic: https://en.wikipedia.org/wiki/Event_(computing)#Event_handler
Delegates are function pointers with context information attached. Say you want to add handlers that act on other elements available in the current context. Like a button that turns an indicator red. Example:
class BuildGui {
Indicator indicator;
Button button;
this(){
... init
button.clickHandler({ // curly braces: implicit delegate in this case
indicator.color = "red"; // notice access of BuildGui member
});
button.clickHandler(&otherClickHandler); // methods of instances can be delegates too
}
void otherClickHandler(){
writeln("other click handler");
}
}
In this imaginary Button class all click handlers are saved to a list and called when it is clicked.
There were several questions in the OP. I am going to try to answer the following two:
Q: Could you show examples of D callbacks and explain where they can be helpful?
A: They are commonly used in all languages that support delegates (C# for an example) as event handlers. - You give a delegate to be called whenever an event is triggered. Languages that do not support delegates use either classes, or callback functions for this purpose. Example how to use callbacks in C++ using the FLTK 2.0 library: http://www.fltk.org/doc-2.0/html/group__example2.html. Delegates are perfect for this as they can directly access the context. When you use callbacks for this purpose you have to pass along all the objects you want to modify in the callback... Check the mentioned FLTK link as an example - there we have to pass a pointer to the fltk::Window object to the window_callback function in order to manipulate it. (The reason why FLTK does this is that back FLTK was born C++ did not have lambdas, otherwise they would use them instead of callbacks)
Example D use: http://dlang.org/phobos/std_signals.html
Q: Why I can't simply pass one function to another and need to wrap it to Delegate?
A: You do not have to wrap to delegates - it depends what you want to accomplish... Sometimes passing callbacks will just work for you. You can't access context in which you may want to call the callback, but delegates can. You can, however pass the context along (and that is what some C/C++ libraries do).
I think what you are asking is explained in the D language reference
Quote 1:
A function pointer can point to a static nested function
Quote 2:
A delegate can be set to a non-static nested function
Take a look at the last example in that section and notice how a delegate can be a method:
struct Foo
{
int a = 7;
int bar() { return a; }
}
int foo(int delegate() dg)
{
return dg() + 1;
}
void test()
{
int x = 27;
int abc() { return x; }
Foo f;
int i;
i = foo(&abc); // i is set to 28
i = foo(&f.bar); // i is set to 8
}
There are already excellent answers. I just want to try to make simple summary.
Simply: delegate allows you to use methods as callbacks.
In C, you do the same by explicitly passing the object (many times named context) as void* and cast it to (hopefully) right type:
void callback(void *context, ...) {
/* Do operations with context, which is usually a struct */
doSomething((struct DATA*)context, ...);
doSomethingElse((struct DATA*)context, ...);
}
In C++, you do the same when wanting to use method as callback. You make a function taking the object pointer explicitly as void*, cast it to (hopefully) right type, and call method:
void callback(void* object, ...) {
((MyObject*)object)->method(...);
}
Delegate makes this all implicitly.

Is there an operator or provision in RxJS to call every time a function is called?

I have a function className.doSomething() which returns an observable.I want to know the time when this function was called or subscribed.
className.doSomething()
:callAtSubscribe( "print current time")
:tap()
:subscribe()
Need something appropriate in place of callAtSubscribe.
You can wrap the method in an Observable.Create. This will allow you to track when the subscription is made. If you then wrapped that in a method, you could track when the method was called. This would allow you to see when the method was called (but potentially not subscribed to the result).
/**
* Module dependencies.
*/
var Rx = require('rx');
Rx.Observable.prototype.log = function (logger, sourceName) {
var source = this;
logger.debug({source : sourceName, kind : 'Created'});
return Rx.Observable.create(function(observer) {
logger.debug({source : sourceName, kind : 'Subscribe'});
return source.subscribe(observer);
});
};
This is a very cut down version of a log method I use. It can be heavily modified to include timings, wiretap of values, error, completions and terminations.