My current task is to extend some JavaScript of a framework we are using. A pop-up should slide in, instead of just appear in the middle of the window. So I have overridden one of the framework's methods, and do at the end this:
AdfDhtmlPage.prototype.showMessages = function (componentId) {
// Some code here
function slideIn() {
var maxTop = windowHeight - (thisHeight + 18);
var tempTop = parseInt(popupElement._rootElement.style.top);
if (maxTop >= tempTop) {
setTimeout(function () {
AdfPage.PAGE.clearMessages(componentId);
},5000);
return;
}
popupElement._rootElement.style.top = tempTop - 1 + 'px';
setTimeout(slideIn, 20);
}
slideIn();
}
Everything worked just fine, but then I thought that the slideIn
method should somehow be a behavior of the popupElement
.
During refactoring I encountered a behavior that was new to me and which is here called binding loss.
So what I came up with is this:
AdfDhtmlPage.prototype.showMessages = function (componentId) {
// Some code here
popupElement._slideIn(popupElement, componentId);
}
AdfDhtmlSimpleFloat.prototype._slideIn = function(element, componentId) {
var maxTop = AdfAgent.AGENT.getWindowHeight() - (element.getHeight() + 18);
var thisTop = parseInt(element._rootElement.style.top);
if (maxTop >= thisTop) {
setTimeout(function () {
AdfPage.PAGE.clearMessages(componentId);
},5000);
return;
}
element._rootElement.style.top = thisTop - 1 + 'px';
setTimeout(function() {
element._slideIn(element, componentId);
}, 20);
}
So when calling the _slideIn
method of popupElement
I need to pass popupElement
as argument. So I can access the objects properties, after the method has been called via setTimeout
(When the binding loss happens).
However, this seems odd to me. So I would like to ask you to review my design. Maybe someone comes up with a better solution?
that was, what I wanted to do:
AdfDhtmlPage.prototype.showMessages = function (componentId) {
// Some code here
popupElement._slideIn(componentId);
}
AdfDhtmlSimpleFloat.prototype._slideIn = function(componentId) {
var maxTop = AdfAgent.AGENT.getWindowHeight() - (this.getHeight() + 18);
var thisTop = parseInt(this._rootElement.style.top);
if (maxTop >= thisTop) {
setTimeout(function () {
AdfPage.PAGE.clearMessages(componentId);
},5000);
return;
}
this._rootElement.style.top = thisTop - 1 + 'px';
setTimeout(this._slideIn, 20);
}
1 Answer 1
The problem is that this._slideIn
refers to a function, not a method invocation. In your third code sample, changing your last line to
var self = this;
setTimeout(function() { self._slideIn(componentId) }, 20);
should be sufficient. You have to capture this
in the closure that you pass to setTimeout()
, because when the code runs later, this
will refer to something else in that execution context.
-
\$\begingroup\$ This did it. Could you please elaborate on this? I debugged it and don't understand it. Now at every call,
this
references theAdfDhtmlSimpleFloat
object. Why is this so? \$\endgroup\$Angelo.Hannes– Angelo.Hannes2013年09月05日 09:23:57 +00:00Commented Sep 5, 2013 at 9:23 -
\$\begingroup\$ You would be better off taking this up on StackOverflow. Here's the background and a reformulation of your question. \$\endgroup\$200_success– 200_success2013年09月05日 09:46:36 +00:00Commented Sep 5, 2013 at 9:46
popupElement
is anAdfDhtmlSimpleFloat
object. We are aware of the possible draw-backs of using their classes, but didn't see any other way. \$\endgroup\$this
for examplethis._rootElement.style.top
. \$\endgroup\$AdfDhtmlSimpleFloat
prototype before trying to call the function? Here is a super simple example jsfiddle.net/yvJfw/2, comment and uncomment the calls to updateElem to see. \$\endgroup\$