Home > Blockchain >  Which event to trigger, programmatically simulating user blur
Which event to trigger, programmatically simulating user blur

Time:12-08

I'm using Power Automate Desktop with an Execute Javascript flow to try to automate some user entry in a Quickbooks Online Payroll form.

When natively using the form, it seems there is an event triggered on blur to validate the numerical input, among other things.

Using the JS flow, updating the input values is not being recognized by the form as once I save it, it shows those inputs as empty.

So I thought I need to trigger the blur event to get the data to save. Here is my JS script:

function ExecuteScript() { 
   var $payrollTableRows = $("table").first().find("tbody > tr.enabled");
   var $regHoursInput;
   var decRegHours;
   var $bonusInput;
   var employeeName;
   
   console.log('Power Automate: Rows Found: '   $payrollTableRows.length);
   
   $payrollTableRows.each(function(){
   
        employeeName = $(this).find("td:eq(1)").find("a").text();
        
            $regHoursInput = $(this).find("input[wageitemid='HOURLY_PAY']");
            if($regHoursInput){
                    decRegHours = Number($regHoursInput .val());
                    
                    $bonusInput = $(this).find("input[wageitemid='BONUS']");
                    $bonusInput.focus();
    
                    if($bonusInput){
                        $bonusInput.val(decRegHours);
                        $bonusInput.trigger('blur');
                    } 
                } 
    });
}

Here is the script that gets executed on focus and blur on the QB Payroll page. enter image description here

Why does the script initiated triggers not fire this code?

UPDATE 1: Adding image of page: payroll page

CodePudding user response:

I don't have QB but I put together a quick html page with a script.

This is the html

    <!DOCTYPE html>
<html lang="en">
<head>    
</head>
<body>
    <div >
        <table >
            <thead>
                <tr>
                    <th>Column 1</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Value <input type="text" id="text-1-input" onblur="txtOnblur();">1</td>
                </tr>
                <tr>
                    <td>Value <input type="text" id="text-2-input" hidden></td>
                </tr>
                
            </tbody>
        </table>
    </div>    
    <script src="https://code.jquery.com/jquery-3.6.1.slim.min.js"></script>
    <script>
        function txtOnblur(){
            $("#text-2-input").show(true);
            $("#text-2-input").val('blur triggered!');
        }
    </script>
</body>
</html>

When I run the following script on the page with Power automate it triggers the onblur event on the textbox

function ExecuteScript() {
var $txt = $("input[id='text-1-input']");
      $txt[0].onblur();
}

In action:

enter image description here

When I try and call the code in a similar way as you do I only get the list of controls linked to the blur event.

enter image description here

I'm assuming it's jQuery being used in QB. I tend to stick to native JavaScript when it comes to PAD, more typing, but less abstraction.

CodePudding user response:

To do something similar without relying on the JavaScript you could use a variable and loops.

Html used for this flow:

<!DOCTYPE html>
<html lang="en">
<head>    
</head>
<body>
    <div >
        <table >
            <thead>
                <tr>
                    <th>Column A</th>
                    <th>Column B</th>
                    <th>Column C</th>
                    <th>Column D</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>A <input type="text" id="text-1-input" value="One"></td>
                    <td>B <input type="text" id="text-2-input" value="Two"></td>
                    <td>C <input type="text" id="text-3-input" value="Three"></td>
                    <td>D <input type="text" id="text-4-input" value="Four"onblur="txtOnblur();"></td>
                </tr>
                <tr>
                    <td><input type="text" id="text-5-input" ></td>
                    <td><input type="text" id="text-6-input" ></td>
                    <td><input type="text" id="text-7-input" ></td>
                    <td><input type="text" id="text-8-input" hidden></td>
                </tr>
                
            </tbody>
        </table>
    </div>    
    <script src="https://code.jquery.com/jquery-3.6.1.slim.min.js"></script>
    <script>
        function txtOnblur(){
            $("#text-8-input").show(true);
            $("#text-8-input").val('blur triggered!');
        }
    </script>
</body>
</html>

I used a bit of JavaScript to extract the number of columns and rows in the table, this could have been done with the flow function 'Extract data from web page', but I find the JavaScript a bit faster/easier.

function ExecuteScript() {
var table = document.querySelector('body > div > table');
var colCount = table.children[0].children[0].children.length;
var rowCount = table.children[1].children.length;
return `${colCount} ${rowCount}`
}

Declare one UI element of the first input box. You can reuse this element by replacing/changing the selector properties to use a variable.

enter image description here

enter image description here

In the flow assign the value that will match the HTML selector for the particular control.

enter image description here

and then use the same element wherever you want to change/extract a value (remember the variable now sets the UI element)

enter image description here enter image description here enter image description here

The full flow code (copy this and paste it to PAD to see the details) There will be errors on your side, but you will see the flow.

WebAutomation.LaunchEdge.AttachToEdgeByUrl TabUrl: $'''http://localhost/stackoverAnswer/''' AttachTimeout: 5 BrowserInstance=> Browser
WebAutomation.ExecuteJavascript BrowserInstance: Browser Javascript: $'''function ExecuteScript() {
var table = document.querySelector(\'body > div > table\');
var colCount = table.children[0].children[0].children.length;
var rowCount = table.children[1].children.length;
return `${colCount} ${rowCount}`
}''' Result=> cols_rows
Text.SplitText.Split Text: cols_rows StandardDelimiter: Text.StandardDelimiter.Space DelimiterTimes: 1 Result=> ColsAndRows
Text.ToNumber Text: ColsAndRows[0] Number=> numCols
Text.ToNumber Text: ColsAndRows[1] Number=> numRows
LOOP colIdx FROM 1 TO numCols STEP 1
    SET inputBoxVariable TO $'''text-%colIdx%-input'''
    WebAutomation.GetDetailsOfElement BrowserInstance: Browser Control: appmask['Web Page \'http://localhost/stackoverAnswer/\'']['Input text \'text-1-input\''] AttributeName: $'''Own Text''' AttributeValue=> inputBoxValue
    IF colIdx = 4 THEN
        WebAutomation.Focus.Focus BrowserInstance: Browser Control: appmask['Web Page \'http://localhost/stackoverAnswer/\'']['Input text \'text-1-input\''] WaitForPageToLoadTimeout: 60
        MouseAndKeyboard.SendKeys.FocusAndSendKeys TextToSend: $'''{Tab}''' DelayBetweenKeystrokes: 10 SendTextAsHardwareKeys: False
    END
    SET inputBoxVariable TO $'''text-%colIdx   4%-input'''
    IF inputBoxValue <> $'''Three''' THEN
        WebAutomation.PopulateTextField.PopulateTextFieldUsePhysicalKeyboard BrowserInstance: Browser Control: appmask['Web Page \'http://localhost/stackoverAnswer/\'']['Input text \'text-1-input\''] Text: inputBoxValue Mode: WebAutomation.PopulateTextMode.Replace UnfocusAfterPopulate: False WaitForPageToLoadTimeout: 60
    ELSE
        WebAutomation.PopulateTextField.PopulateTextFieldUsePhysicalKeyboard BrowserInstance: Browser Control: appmask['Web Page \'http://localhost/stackoverAnswer/\'']['Input text \'text-1-input\''] Text: $'''Skip this one''' Mode: WebAutomation.PopulateTextMode.Replace UnfocusAfterPopulate: False WaitForPageToLoadTimeout: 60
    END
END

How it runs:

enter image description here

  • Related