vagabond719

Value of JS variable in IE

24 posts in this topic

At work I use a ticketing system called ServiceNow. I can run scripts using this example $oIE.document.parentWindow.execScript. I am able to create a JS variable using the execScript method. Though it does not return a value. I can see the variable I need from the console. I have seen in the past $oIE.document.parentWindow.eval was used but this does not seem to work with IE 11. Is there anyway to pull a JS variable into Autoit? Currently I am writing the results of one of the ServiceNow queries to an empty text box but I am hoping for another option. 

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

You create it , but do you assign a value to it? If it is 'empty' it is normal not to return any value!

Edited by Juvigy
spell check

Share this post


Link to post
Share on other sites

I've done some tests (a bit botched) about this matter in this my topic and found (in my opinion) some interesting points:

1) you shouldn't use the execscript method since is no longer supported, use  eval instead(source is here: https://msdn.microsoft.com/en-us/library/ms536420(v=vs.85).aspx
2) to access javascript variables from AutoIt script you should:
create a reference to the Javascript Global Object within your HTML page using this code in the <head> session: (source is here: http://stackoverflow.com/questions/9642491/getting-a-reference-to-the-global-object-in-an-unknown-environment-in-strict-mod   (see first answer)) 

<script type="text/javascript">
        var JSglobal = (1,eval)("this");
</script>

3) from the AutoIt script create an Object Handle to the above reference using this code:

Global $ohJS = $oIE.document.parentwindow.JSglobal ; $ohJS is a reference to the javascript Global Obj

4) Use the $ohJS in your AutoIt script to read a javascript variable from the HTML page in a way like this:

$ohJS.myjsvariable

you can also use $ohJS to call javascript methods and get mthod's result back in an AutoIt variable using the eval method of the global object

Local $result = $ohJS.eval('parseInt( 10000 ).toLocaleString();')
MsgBox(0, "Debug", $result)

see my tests in post #9 and #12 of this topic

p.s.
Sorry if i'm not such clear.... but it works


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

As Servicenow is a webbased GUI why not read the element values itself? Why is javascript needed?

1. use IE.AU3 to get normal findelement and the related value
2. use Simplespy and uiwrappers/cuiautomation (See examples section)
3. Call somehow the javascript as Chimp gives examples on
4. use webdriver https://www.mkyong.com/selenium/how-to-execute-javascript-in-selenium-webdriver/

1 is easiest and 4 is hardest 

edit: an additional one can just be to do a sendkeys to the addressbar with a value:

javascript: alert(document.body.innerHTML);

Edited by junkew

Share this post


Link to post
Share on other sites

Chimp,

When I use _IEAttach I am not able to call any value like this $oIE.document.parentwindow.JSglobal. I can via the browser console. Are you using _IEAttach and what browser are you using?

Share this post


Link to post
Share on other sites

I see Chimp you are using ObjCreate("Shell.Explorer.2") vs ObjCreate("InternetExplorer.Application") in the IE.au3. I was able to take one of your examples and it works on my PC. Do you know if it is possible to attach to an open IE window with this type of object? I am trying to research it now. 

Share this post


Link to post
Share on other sites

Junkew,

I was reading over your suggestions these look great from an automation stand point. My issue is I need to run glide queries in ServiceNow. I can run the queries via JS but I am using execScript because eval does not work. So I am stuck saving the results of the JS to an element so I can bring it into AutoIt. Otherwise I do go directly for the element. 

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

If you see it in your html of IE by viewing source you should be able to get it out. some tricks are nicer then others.

You can append the html with a 1 pix textbox with body.append and fill that with js and read it with ie.au3

See 

www.autoitscript.com/forum/topic/177711-wait-until-part-of-web-page-loads/

 

Edited by junkew

Share this post


Link to post
Share on other sites

Here is an example of a Glide Query. As you can see it has nothing to do with an element on the page. This particular query is to pull the requestor of the parent ticket email address. 

var MainAppWin = "undefined" != typeof g_form ? window : document.getElementById("gsft_main").contentWindow,
    gr = new MainAppWin.GlideRecord("x_human_access_request");
gr.addQuery("sys_id", MainAppWin.g_form.getValue("parent")), gr.query(function(e) {
    if (e.next()) {
        var n = new MainAppWin.GlideRecord("sys_user");
        n.addQuery("sys_id", e.getValue("opened_by")), n.query(function(e) {
            e.next() && MainAppWin.g_form.setValue("close_notes", e.email)
        })
    }
});

Share this post


Link to post
Share on other sites

#10 ·  Posted

On 8/11/2016 at 5:32 PM, vagabond719 said:

I see Chimp you are using ObjCreate("Shell.Explorer.2") vs ObjCreate("InternetExplorer.Application") in the IE.au3. I was able to take one of your examples and it works on my PC. Do you know if it is possible to attach to an open IE window with this type of object? I am trying to research it now. 

.... I do not know why this method works on the Browser Control but it doesn't in the Internet Explorer Window.

following scripts show the issue,
First script uses the Browser Control and will create the reference to the Javascript global obj in AutoIt

through this reference we can access javascript variables and more...

Second script uses the Internet Explorer Application instead and will fail on the attempt to reference to the Javascript global obj.

I'm wondering why this happens and if there is a solution?
if someone knows why, I would be also glad to know

First script uses the Browser Control and successfully creates the Javascript global object variable

#include <ie.au3>

Local $hGUIMain = GUICreate("Browser", @DesktopWidth / 2, @DesktopHeight / 2)
GUISetState() ;Show GUI

; We prepare the Browser Control as our test subject
Global $oIE = ObjCreate("Shell.Explorer.2")
$hIE = GUICtrlCreateObj($oIE, 0, 0, @DesktopWidth / 2, @DesktopHeight / 2) ; <- embedd $oIE in the AutoIt GUI
$oIE.navigate('www.google.com')
Sleep(3000)

Local $oDocument
Do
    Sleep(250)
    $oDocument = $oIE.document
Until IsObj($oDocument)

; get reference to the <head> tag
Local $oHead = _IETagNameGetCollection($oIE, "head", 0)

; we inject in the html page, within the <head> session, some <a> elements containing our javascript code

; this javascript will create the variable JSgloba containing a reference to the javascript globa object
; (and will also fire a popup just to show that this snippet was executed)
Local $sJSCode_0 = '<a id="mylink"; href=' & "'javascript:var JSglobal = (1,eval)(" & '"this");  alert("Debug: javascript executed"' & ");  void(0);'>"

; this javascript will fire a popup to show that the JSglobal obj variable exists
; we know that it exist because we use a method from this variable within the alert()
Local $sJSCode_1 = '<a id="checkvar"; href=' & "'javascript: alert(" & '"Debug: Javascript engine build version is " + JSglobal.ScriptEngineBuildVersion()' & ");  void(0);'>"

; --- THE INSERTION ORDER IS IMPORTANT. DO NOT CHANGE ORDER
_IEDocInsertHTML($oHead, $sJSCode_1, "afterbegin")
_IEDocInsertHTML($oHead, $sJSCode_0, "afterbegin")
; ----------------------------------------------------------

Local $oLink
; get a reference to proper <a> elements
$oLink = _IEGetObjById($oIE, "mylink") ; First <a> Javascript to create the variable JSglobal
; and execute it's javascript
$oLink.click() ; execute javascript_0

$oLink = _IEGetObjById($oIE, "checkvar") ; Second <a> Javascript for debug purpose
$oLink.click() ; execute javascript_1

; this shoul get reference to the JSglobal obj variable from javascript to AutoIt
; THIS WORKS IN AN EMBEDDED BROWSER CONTROL BUT DOES NOT WORKS IN AN INTERNET EXPLORER BROWSER WINDOW
Global $ohJS = $oIE.document.parentwindow.JSglobal ; $ohJS is a reference to the javascript Global Obj

MsgBox(0, "Debug from AutoIt", "Javascript global obj created in AutoIt. " & IsObj($ohJS))

Second script will fail on the attempt to reference to the Javascript global obj

#include <ie.au3>
Local $oIE = _IECreate("www.google.com")

Local $oDocument
Do
    Sleep(250)
    $oDocument = $oIE.document
Until IsObj($oDocument)

; get reference to the <head> tag
Local $oHead = _IETagNameGetCollection($oIE, "head", 0)

; we inject in the html page, within the <head> session, some <a> elements containing our javascript code

; this javascript will create the variable JSgloba containing a reference to the javascript globa object
; (and will also fire a popup just to show that this snippet was executed)
Local $sJSCode_0 = '<a id="mylink"; href=' & "'javascript:var JSglobal = (1,eval)(" & '"this");  alert("Debug: javascript executed"' & ");  void(0);'>"

; this javascript will fire a popup to show that the JSglobal obj variable exists
; we know that it exist because we use a method from this variable within the alert()
Local $sJSCode_1 = '<a id="checkvar"; href=' & "'javascript: alert(" & '"Debug: Javascript engine build version is " + JSglobal.ScriptEngineBuildVersion()' & ");  void(0);'>"

; --- THE INSERTION ORDER IS IMPORTANT. DO NOT CHANGE ORDER
_IEDocInsertHTML($oHead, $sJSCode_1, "afterbegin")
_IEDocInsertHTML($oHead, $sJSCode_0, "afterbegin")
; ----------------------------------------------------------

Local $oLink
; get a reference to proper <a> elements
$oLink = _IEGetObjById($oIE, "mylink") ; First <a> Javascript to create the variable JSglobal
; and execute it's javascript
$oLink.click() ; execute javascript_0

$oLink = _IEGetObjById($oIE, "checkvar") ; Second <a> Javascript for debug purpose
$oLink.click() ; execute javascript_1

; this shoul get reference to the JSglobal obj variable from javascript to AutoIt
; THIS WORKS IN AN EMBEDDED BROWSER CONTROL BUT DOES NOT WORKS IN AN INTERNET EXPLORER BROWSER WINDOW
Global $ohJS = $oIE.document.parentwindow.JSglobal ; $ohJS is a reference to the javascript Global Obj

MsgBox(0, "Debug from AutoIt", "Javascript global obj created in AutoIt. " & IsObj($ohJS))

 


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#11 ·  Posted

Chimp,

Do you know of a way to bind to an open IE window after creating the ObjCreate("Shell.Explorer.2")?

Share this post


Link to post
Share on other sites

#13 ·  Posted

i found a workaround, that works for me:

#include <IE.au3>
Global $oIE = _IECreate("about:blank")
Global $eval = 0
$oIE.Document.parentWindow.execScript("document.body.oAutoIt = eval;")
$eval = Execute("$oIE.Document.body.oAutoIt")
If IsObj($eval) Then
    MsgBox(0, "eval", $eval('typeof "str"'));execute js and get return
    $eval("alert('test');")
EndIf

hope it's useful to someone :D

2 people like this

Share this post


Link to post
Share on other sites

#14 ·  Posted

On 11/11/2016 at 7:06 PM, genius257 said:

i found a workaround, that works for me:

Nice Shot @genius257!
you should anyway try to achieve the same result without the execScript method (seems that execScript is going to be dismissed. see here: https://msdn.microsoft.com/en-us/library/ms536420(v=vs.85).aspx ). I tryed to achieve the same result without the execScript method in post #10, but I failed miserably.... :'(
Hope you will come out also with something that doesn't relies on the javascript ecexScript method.... :)


p.s.
also, why you used the AutoIt Execute function?,

$eval = Execute("$oIE.Document.body.oAutoIt")

seems that it works also directly without the Execute, like this

$eval = $oIE.Document.body.oAutoIt

 


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#15 ·  Posted

Thanks @Chimp ;)

10 hours ago, Chimp said:

you should anyway try to achieve the same result without the execScript method (seems that execScript is going to be dismissed. see here: https://msdn.microsoft.com/en-us/library/ms536420(v=vs.85).aspx ). I tryed to achieve the same result without the execScript method in post #10, but I failed miserably.... :'(
Hope you will come out also with something that doesn't relies on the javascript ecexScript method.... :)

Well i am aware of using execScript does present problems for the future. But they promise eval, in which case, the issue solves itself, no?

(also, they say it's staring from IE 11, and that's what I'm using, yet no eval :/ )

10 hours ago, Chimp said:

also, why you used the AutoIt Execute function?

I use Execute, so in case of error, the script won't crash. It's just my quick way to avoid crashes, without catching the errors with something like ObjEvent("AutoIt.Error",...)

Share this post


Link to post
Share on other sites

#16 ·  Posted

7 hours ago, genius257 said:

Well i am aware of using execScript does present problems for the future. But they promise eval, in which case, the issue solves itself, no?

I think that is not exactly like that, execScript() is a method of the javascript window obj, while eval() is a method of the Javascript Global Object. each one belongs to a different object, and both are already present. (perhaps execScript is still there for back compatibility (at least for now...)

Since execScript() is a method of the javascript window obj, you can easily get an handle to it, and you can as well easily call its methods.

eval() is instead a method of the javascript global obj. In the remarks of the msdn documentation about the javascript Global Obj is stated this sentence: "The Global object is never used directly, and cannot be created using the new operator. It is created when the scripting engine is initialized, thus making its functions and constants available immediately."

So, for what I understand, Global Object's methods can be called from within the javascript environment, but you can not create a reference from the outside. (or better, is not as immediate).

To be able to get a reference to the Javascript Global Object, maybe some sort of workaround is to be found.

Here is a question on StackOverflow about this matter with a plausible answer (see first answer)

here and here are two points of an article written by the answerer.

Using the information contained there, I'm been able to get a reference to the Javascript Global Obj only using the "Browser Control" (Shell.Explorer.2).  (First script in above post#10)

I've failed attempting to get the same reference within the Internet explorer browser (using "InternetExplorer.Application" or _iEcreate()) (second script in post#10)

I've also seen by using the ObjName() function, that the Module name in which the object runs is:
1) When I get a reference to the Javascript Global Object from within the Browser control, the ObjName($oIE, $OBJ_MODULE), returns jscript9.dll

2) When I get a reference to the Javascript Global Object from the script provided by @genius257 in post#13, the ObjName($oIE, $OBJ_MODULE), returns OLEAUT32.dll
Also, with that script you get a reference to the eval() function within javascript global obj and not to the Javascript global obj itself.

3) If I use the below script, that is a little variation to @genius's script, I get a reference to the whole Javascript Global Obj instead. I think is better a reference to the whole Obj instead of to its eval() function only.
also, in this last case the ObjName($oIE, $OBJ_MODULE), returns mshtml.dll

#include <IE.au3>
Global $oIE = _IECreate("about:blank")
Global $eval = 0
;  $oIE.Document.parentWindow.execScript("document.body.oAutoIt = eval;") ; this returns a reference to the eval() function only
$oIE.Document.parentWindow.execScript('oAutoIt = (1,eval)("this");') ; this returns a reference to the javascript Global Object
$oIE.Document.parentWindow.execScript('jsVariable = "Hello from Javascript";') ; this declares a javascript variable

; $eval = Execute("$oIE.Document.body.oAutoIt")
$eval = $oIE.Document.parentwindow.oAutoIt

If IsObj($eval) Then
    MsgBox(0, "ObjName", ObjName($eval, 5))

    ; MsgBox(0, "eval", $eval('typeof "str"'));execute js and get return
    MsgBox(0, "eval", $eval.eval('typeof "str"'))

    ; $eval("alert('test');")
    $eval.eval('alert("test");')
    ; this is another method of the Javascript Global Object
    MsgBox(0, "JS engine Build Version", "Javascript engine build version is " & $eval.eval('oAutoIt.ScriptEngineBuildVersion();'))
    MsgBox(0, "value of a js variable", "Javascript variable value is " & @CRLF & @CRLF & $eval.jsVariable)
EndIf

 

anyway, what I think would be interesting, is to find a way to refer the Javascript Global Obj from within the Internet Explorer, without the use of the ExecScript() method.

 


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#17 ·  Posted

Hi @Chimp :) thanks for the extensive reply ^^'

I will look into your information :), thank you.

 

1 hour ago, Chimp said:

 

#include <IE.au3>
Global $oIE = _IECreate("about:blank")
Global $eval = 0
;  $oIE.Document.parentWindow.execScript("document.body.oAutoIt = eval;") ; this returns a reference to the eval() function only
$oIE.Document.parentWindow.execScript('oAutoIt = (1,eval)("this");') ; this returns a reference to the javascript Global Object
$oIE.Document.parentWindow.execScript('jsVariable = "Hello from Javascript";') ; this declares a javascript variable

; $eval = Execute("$oIE.Document.body.oAutoIt")
$eval = $oIE.Document.parentwindow.oAutoIt

If IsObj($eval) Then
    MsgBox(0, "ObjName", ObjName($eval, 5))

    ; MsgBox(0, "eval", $eval('typeof "str"'));execute js and get return
    MsgBox(0, "eval", $eval.eval('typeof "str"'))

    ; $eval("alert('test');")
    $eval.eval('alert("test");')
    ; this is another method of the Javascript Global Object
    MsgBox(0, "JS engine Build Version", "Javascript engine build version is " & $eval.eval('oAutoIt.ScriptEngineBuildVersion();'))
    MsgBox(0, "value of a js variable", "Javascript variable value is " & @CRLF & @CRLF & $eval.jsVariable)
EndIf

 

I like your idea, but your code does not work with me. Also not using Execute, when defining the $eval in AutoIt, forces the script to crash, upon error.

>Running:(3.3.14.2):C:\Program Files (x86)\AutoIt3\autoit3.exe "C:\Users\...\Desktop\script.au3"    
--> Press Ctrl+Alt+F5 to Restart or Ctrl+Break to Stop
"C:\Users\...\Desktop\script.au3" (9) : ==> The requested action with this object has failed.:
$eval = $oIE.Document.parentwindow.oAutoIt
$eval = $oIE.Document.parentwindow^ ERROR
->02:01:20 AutoIT3.exe ended.rc:1
>Exit code: 1    Time: 2.245

 

Share this post


Link to post
Share on other sites

#18 ·  Posted

13 hours ago, genius257 said:

I like your idea, but your code does not work with me. Also not using Execute, when defining the $eval in AutoIt, forces the script to crash, upon error.

indeed, it works on Internet Explorer 9, but it doesn't on Internet Explorer 11 (on IE11 it doesn't works even if you set compatibility mode down to IE9) ... nice effects of the IE upgrades....
Perhaps the issue is due to something listed here... https://msdn.microsoft.com/en-us/library/dn467846(v=vs.85).aspx


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#19 ·  Posted

msdn.microsoft.com/en-us/library/dn384057

Execscript not valid

Share this post


Link to post
Share on other sites

#20 ·  Posted

17 hours ago, junkew said:

msdn.microsoft.com/en-us/library/dn384057

Execscript not valid

Hi @junkew, No, the Execscript method is still working (at least for now), the problem here is that the Javascript Globa Object is no more referenceable from AutoIt, (or better, I am not aware of how), while it was in previous versions of IE instead.
It seems that The Javascript Global Object has been armored and segregated within its own environment only.
(If you know a way to reference the Javascript global object from AutoIt that I am not aware of, this is the answer I'm looking for.)


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now