2

I'm trying to automate the login of my CCTV system's webpage in IE11 using AHK. I think the login page utilises Angular 1.2.0.

Here's my script:

wb := ComObjCreate("InternetExplorer.Application")

wb.Visible := True

wb.Navigate("http://192.168.1.6/doc/page/login.asp")

While wb.readyState != 4 || wb.document.readyState != "complete" || wb.busy ; wait for the page to load
   Sleep, 10

Sleep, 100

username_input := wb.document.getElementById("username")
password_input := wb.document.getElementById("password")

username_input.value := "myusername"
password_input.value := "mypassword"

wb.document.querySelector(".login-btn").click()

Return

The username/password visually populate as I expect, but when the script "clicks" the login button, I get an error message implying the username field is blank. If I manually type and delete a single letter and try again, I get the same message for the password field. If I manually type and delete a single letter in that field, then the login button works.

I've never used Angular, so I've no idea what magic goes on behind the scenes when a user types in a field. How can I make it believe there's something in those fields?

Here's the HTML of the login page, if that helps:

<!doctype html>
<html>
<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" >
    <meta http-equiv="Pragma" content="no-cache" />
    <meta http-equiv="Cache-Control" content="no-cache, must-revalidate" />
    <meta http-equiv="Expires" content="0" />
    <script>
        document.write("<link type='text/css' href='../ui/css/ui.css?version=" + new Date().getTime() + "' rel='stylesheet' />");
    </script>
</head>
<body ng-keypress="docPress($event)" ng-controller="loginController" ng-cloak class="ng-cloak">
<div class="login" id="login">
    <div class="top">
        <div class="logo"></div>
        <div class="language">
            <div class="language-show" ng-click="showLanguageList($event)"><span class="current-language" id="current_language"></span></div>
            <div class="language-list" id="language_list" ng-click="changeLanguage($event)"></div>
        </div>
    </div>
    <table cellspacing="0" cellpadding="0" border="0" class="middle">
        <tr>
            <td class="login-l">&nbsp;</td>
            <td class="login-m">
                <div class="login-part">
                    <div class="line"></div>
                    <div class="login-error">
                        <div class="inputValidTip" ng-show="szErrorTip!=''"><i class='error'></i><label>{{szErrorTip}}</label></div>
                    </div>
                    <div class="login-user">
                        <input type="text" class="login-input" id="username" ng-model="username"maxlength="32" autocomplete="off" placeholder="{{oLan.username}}" />
                        <i class="icon-user"></i>
                    </div>
                    <div class="login-item">
                        <input type="password" class="login-input" id="password" ng-model="password" maxlength="16" placeholder="{{oLan.password}}" />
                        <i class="icon-pass"></i>
                    </div>
                    <div class="login-item">
                        <button type="button" class="btn btn-primary login-btn" ng-click="login()"><label ng-bind="oLan.login"></label></button>
                    </div>
                    <div class="login-item anonymous" ng-show="anonymous">
                        <span ng-bind="oLan.anonymous" ng-click="login('anonymous')"></span>
                    </div>
                </div>
            </td>
            <td class="login-r">&nbsp;</td>
        </tr>
    </table>
    <div class="footer" id="footer"></div>
</div>
<div id="active" class="msg-content-wrap">
    <div class="msg-content">
        <div class="password">
            <span class="desc"><label ng-bind="oLan.username"></label></span>
            <span><label ng-bind="activeUsername"></label></span>
        </div>
        <div class="password">
            <span class="desc"><label ng-bind="oLan.password"></label></span>
            <span><input id="activePassword" type="password" ng-model="activePassword" maxlength="16" onpaste="return false;" /></span>
            <span class="inputValidTip"><i ng-class="{true:'success', false:'error'}[activePasswordStatus]"></i></span>
        </div>
        <div strength class="passwordstrength" lan="oLan" o-password="activePassword" o-username="activeUsername"></div>
        <div class="password">
            <span class="desc"><label ng-bind="oLan.confirm"></label></span>
            <span><input type="password" onpaste="return false;" ng-model="activePasswordConfirm" maxlength="16" /></span>
        </div>
    </div>
</div>
<div id="main_plugin" class="no-window"></div>
</body>
<script id="seajsnode" src="../script/lib/seajs/seajs/sea-2.1.1.min.js"></script>
<script>
    document.write("<script src='../script/lib/seajs/config/sea-config.js?version=" + new Date().getTime() + "' ></scr" + "ipt>");
</script>
</html>

Thanks

Codemonkey
  • 4,455
  • 5
  • 44
  • 76
  • You should manually trigger the browser event for `change` like so `var event = new Event('change'); element.dispatchEvent(event);`. You should try this right after settings the values like you do above. There is an answer here https://stackoverflow.com/a/23612498/61577 – cleftheris Mar 30 '20 at 11:22
  • I added these lines and it's made no difference: `event := wb.document.createEvent("Event")`, `event.initEvent("change", true, true)`, `username_input.dispatchEvent(event)`. I still get a message saying that the username field is blank. What am I doing wrong? – Codemonkey Mar 30 '20 at 11:48
  • Your argument passed in `document.createEvent("Event")` is wrong. According to [MDN createEvent](https://developer.mozilla.org/en-US/docs/Web/API/Document/createEvent) possible event types include "UIEvents", "MouseEvents", "MutationEvents", and "HTMLEvents". So stick to "HTMLEvents" in your case – cleftheris Mar 30 '20 at 11:59
  • I've made that change, it still doesn't work. Any other ideas? – Codemonkey Mar 31 '20 at 06:59

1 Answers1

1

Couldn't you focus or click on the elements and then send the data with one of the several send types until you find one that works? Sometimes it helps to send a letter and a backspace then wait to send the data then wait .2 sec and send tabs to next field (or repeat the process:

...
wb.document.getElementById("username").click() ; or .focus()
SendInput, x{bs}
Sleep, 200
SendInput, myusername
Sleep, 200
SendInput, {tab} ; or {tab x} to pw field and skip next line
wb.document.getElementById("password").click()
Sleep, 200
SendInput, mypassword
Sleep, 200
SendInput, {tab}
...

Try it and see . . .

EDIT Per OP success with:

....
username_input := wb.document.getElementById("username")
username_input.focus() 
SendInput, myusername{tab}
SendInput, mypassword{enter}
PGilm
  • 2,262
  • 1
  • 14
  • 26
  • Perfect, thank you. Being a complete newbie to AHK I had no idea there was a SendInput, though with hindsight it's obvious and I should have sought it out. This is what I went with: ```username_input.focus() \\\\ SendInput, myusername \\\\ Sleep, 200 \\\\ password_input.focus() \\\\ SendInput, mypassword \\\\ Sleep, 600 \\\\ wb.document.querySelector(".login-btn").click()``` – Codemonkey Apr 03 '20 at 07:04
  • 1
    Actually as you suggested, if I try tab I can do away without the Sleep inputs and it's obviously much faster (200 & 600 were the lowest it seemed I could reliably go): ```username_input.focus() \\\\ SendInput, myusername \\\\ SendInput, {tab} \\\\ SendInput, mypassword \\\\ SendInput, {enter}``` – Codemonkey Apr 03 '20 at 07:08
  • 1
    Which I now know can be further shortened to ```username_input.focus() \\\\ SendInput, myusername{tab} \\\\ SendInput, mypassword{enter}``` – Codemonkey Apr 03 '20 at 09:11
  • Great result. Thx for following up. My EDITED part has your final result too. – PGilm Jun 25 '20 at 20:58