Understanding the scope of "this" in Browser script

Due to the un-holy interest in the browser script tracing feature of the ImposSiebel Toolbar poll, this article is a little treat for all the closet Browser Script fans out there.

The behaviour described below is fundamental to ECMA script, but will catch most Siebel professionals off guard, and theres a very good reason for this.

Lets start with an example to set the scene. This scenario is lifted from the following Article on the Siebel Support Website, and summarised below.

[Goal]
How Can You Use Browser Script in Siebel 7 onwards to Set Focus on a Different Applet or Control? [ID 477070.1]

[Solution]
1. Query for the applet that you want to receive focus. Add the following to the (general) (declarations) section of the browser script:

setTimeout("DoSetFocus()",1000);


2. Create the following function

function DoSetFocus()
{
var appFocus = theApplication().FindApplet("Account Entry Applet");
var objControl = appFocus.FindActiveXControl("MainPhoneNumber");
if (objControl.canHaveHTML == false) {
objControl.focus();
} else {
objFocus = objControl.getElementsByTagName("Input");
objFocus = objFocus[0];
objFocus.focus();
}
}

Since there is no error handling provided by the Siebel examples, we'll add some of our own.

1. We'll modify the solution a little, and put the setTimeOut in the Applet load section.


function Applet_Load ()
{
try {
setTimeout("DoSetFocus()",1000);
} catch(e) {
//handle error here
alert( e.toString() );
}
finally {
}
}


2. And here is the set focus function with a try/catch, but instead of hard coding the applet name, we'll just use this.Name().


function DoSetFocus()
{
try {
var appFocus = theApplication().FindApplet( this.Name() );
var objControl =
appFocus.FindActiveXControl("MainPhoneNumber");//change this to a valid
control

if (objControl.canHaveHTML == false) {
objControl.focus();
} else {
objFocus = objControl.getElementsByTagName("Input");
objFocus = objFocus[0];
objFocus.focus();
}

} catch(e) {
//bubble the error back up the chain to be handled
throw ( " > DoSetFocus > "+ e.toString() );
} finally {
}
}


3. Compile and run it.

If you've tried it, you will notice that all it does, is generate an IE javascript error.

We expect this code to get into DoSetFocus, and set focus to our desired field, and if there is any error, it should throw an error back to the caller, which will be handled by the alert() in Applet_Load.

So can anyone see anything wrong with this code?
There are actually two fundamental flaws.

To prevent any spoilers, do not scroll down any further, scroll back up now....




























If you've gotten this far accidentally, and wondered ...WHAT THE HECK WAS THAT? That is "Modern Talking", the best of 80s music from Europe.

This will bring back some good memories for GenX europeans, but for our majority US readers, i apologize, because sadly, Pop synth never caught on in the US, Australia or the UK, but in Europe and Asia this band was as big as the Beattles.

"You're my heart, you're my soul" was a master piece from this classic german duo.

If you are still following this genre, Thomas Anders "Good Karma (2009)", has that classic Modern Talking sound that is so hard to find now days.



And for good measure, you cannot mention MT without Sandra Cretu. Again for our US readers, MT and Sandra's success can be closely paralleled to MJ and Madonna in the states. If i could only pick one Sandra song, it would be "Maria Magdalena", this is quintisential 80s pop synth, and unmistakable euro disco.

This is your last chance, if you dont want to be spoiled, go back now, but if you've endured through that, it means you really want to know the answer by now...

Okay, have you had enough of 80s German pop bands? Here is the answer

[Issue 1]
the throw from DoSetFocus() is not caught


This should be self explanitory, the root of the function is no longer Applet_Load, so when we try to throw the error, there is no one there to
catch it.

The setTimeOut function causes the scope to change, and DoSetFocus becomes the root calling function. With that in mind, we just need to change the throw to an alert to handle the error.


[Issue 2]
this.Name() is out of scope


this.Name() will return the name of the current Applet inside the vanilla
applet events (listed below)

Applet_PreInvokeMethod
Applet_InvokeMethod
Applet_ChangeRecord
Applet_ChangeFieldValue
Applet_Load

But when it is used in a custom function or the declarations section, the behaviour is different.

[So what does 'this' refer to?]

'this' can refer to the parent or current object depending on the current context.

In the case above, under the vanilla events, 'this' refers to the current applet, but inside a custom function 'this' actually refers to the view frame.

This isnt a bug, and the behaviour is expected, if we understand how these functions are created or instantiated by Siebel. The exact mechanism behind this behaviour deserves another article, but for now just keep this behaviour in mind when designing your functionality.

If you want to reference the current applet, in our custom functions, the workaround is quite simple, just use a global pointer to the current object.

Under your (declarations) section put this code


var that = this;


Now, we can reference the current applet correctly in every function, by using that.Name()

After writing this article, i found this document on Siebel Support

What Is the Scope of the "this" Object in Browser Script? (Doc ID477659.1).

This article documents this behaviour just as i have, spooky!

There is an important point worth taking from this Siebel article. Any code that is written in the declarations of an applet, is shared among all the other applets in the same view.

This is because the code that is written in the declarations section is part of the view frame, and since all the applets are part of the same container, all the variables will be shared.

Let me put together a diagram, so we can see it visually...Here it is.



It just occured to me, this diagram reveals something i never thought about before, are you guys thinking what i'm thinking? This really belongs in the next article.

But to conclude this topic, there is something about Siebel (Doc ID 477659.1) that i would like to add. In this arcticle it states...


"In server script:

The this or Me object is the object whose script you are editing at the moment.".


What its saying is, if you are on a BC, this.Name(), will always return the name of the BC no matter which function you call it from, likewise for applets, and business services, this.Name() will return the name of the object you are in.

The author who wrote this support web document, had Siebel professionals in mind, and while this is true in most cases, it is not not entirely accurate.

In the continuation of this article, i'll show you an exception to this rule, and the reason for this, is the same reason why the scope is different in Browser script.


1 comment:

  1. nice post but it made me a little bit confused actually may be i have to read the continuation of it.

    ReplyDelete

Comments are open to all, please make it constructive.