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.
Why does the script initiated triggers not fire this code?
UPDATE 1: Adding image of 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:
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.
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.
In the flow assign the value that will match the HTML selector for the particular control.
and then use the same element wherever you want to change/extract a value (remember the variable now sets the UI element)
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: