Which event to trigger, programmatically simulating user blur - javascript

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:
UPDATE 2:
Posting the PAD flow I used. Also got a good overview of this from this video. And how to use Loop and Loop Index from this article.
My Flow:

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 class="table-responsive">
<table class="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:

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 class="table-responsive">
<table class="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.

Related

jQuery copy and append a row with changes

I'm trying to copy a row, change some data, then append it to the end of a table:
$(document).ready(function(){
$("#show_new_rows_number").change(function(){
var table_body = $("tbody");
var master_row = table_body.clone().children('tr')[mr_selector];
master_row.children('td')[0].children('input').first().name = 'type['+(rows+1)+']';
master_row.children('td')[1].children('input').first().name = 'type['+(rows+1)+']';
});
});
Here's the HTML:
<html>
<head>
<title>Test</title>
</head>
<body>
<table>
<thead>
<tr>
<th>First Name:</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="first_name[1]"></td>
<td><input type="text" name="last_name[1]"></td>
</tr>
</tbody>
</table>
<input type="number" min=1 max=10 value=1 id="show_new_rows_number">
</body>
</html>
I'm getting an error that master_row.children is not a function. I really stink at traversing and doing anything in Javascript when it comes to DOM manipulation. Please help! I haven't even gotten to appending the row to the table yet and already getting errors.
The problem is that the elements returned from the jQuery's .children() method, are not jQuery elements, they are HTML elements, thus they do not have any .children() method.
So, assuming that the rest of the code is correct (since this seems to be just a part of the javascript code), your code should be:
$(document).ready(function(){
$("#show_new_rows_number").change(function(){
var table_body = $("tbody");
var master_row = table_body.clone().children('tr')[mr_selector];
$(master_row.children('td')[0]).children('input').first().name = 'type['+(rows+1)+']';
$(master_row.children('td')[1]).children('input').first().name = 'type['+(rows+1)+']';
});
});
O such cases, use the developer tools to print some values on the console. If you run console.log($("tbody").clone().children('tr')[mr_selector].children('td')[0]); you will get just a HTML element, not an jQuery element.

Delete table row (from a loop an api) by using curl

I am using a for-loop for displaying data from an API inside a table:
for ($i = 0; $i < count($return['data']); $i++){
echo "<tr><td>".$return['data'][$i]['data_id']."</td>";
echo "<td>".'<button id="delete" class="btn btn-danger" value="'.$return['data'][$i]['data_id'].'" type="text">Delete</button>'."</td></tr>";
}
The result is a table that shows the data_id and the delete button in a row. Now, I want to be able to delete the item by sending the data_id to curl-> delete (API) code when the delete button clicked!
Or run below code on the delete button clicked.
curl --include \
--request DELETE \
--header "<secret key>" \
https://example.com/api/v1/data/{data_Iid}?app_id={appId}
and I need to include the data_id from the loop and pass it to the curt delete code. I used a onClick function to get the value of data_id but it just shows only the first data_id value for each delete button.
How can I achieve my goal and be able to pass the right data_id to curl delete code?
Thanks.
For performance reasons I 'd place an event listener on the table. One JavaScript event listener can catch all clicks on a button. Have a look at the following example.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Button Value Event Listener</title>
</head>
<body>
<table id="my-table">
<thead>
<tr>
<th>Spalte 1</th>
<th>Spalte 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Wert 1</td>
<td>
<button value="1" name="delete[]">Mein Button</button>
</td>
</tr>
<tr>
<td>Wert 2</td>
<td>
<button value="2" name="delete[]">Mein Button</button>
</td>
</tr>
</tbody>
</table>
<script>
var table = document.getElementById('my-table');
table.addEventListener('click', function(event) {
var target = event.target;
if (target.tagName = 'BUTTON' && target.value) {
// remove and place your ajax request here
console.log(target.value);
}
});
</script>
</body>
</html>
With this example you 'll get all values you 've placed in your for-loop for the buttons. Please make sure, that $return['data'][$i]['data_id'] is set and contains the value you expect.
In the geiven example your id is just logged in the console. Please replace the console.log with your asynchronous javascript request (AJAX).

How to get a number value from an input field?

I have some issues with calculating some stuff with JS and getting the right values out of the input fields (number). When I use this code it doesn't show anything. So what is wrong with my JS? Do I need to include a jQuery file?
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
</head>
<body>
<form id="frm1" action="Calculate.html">
<table width="350px" border="1px">
<tr>
<th colspan="2">Availability</th>
</tr>
<tr>
<td>Total Production Time</td>
<td><input type="number" name="TotalProductionTime" placeholder=""> hours</td>
</tr>
<tr>
<td>Breaks</td>
<td><input type="number" name="Breaks" placeholder=""> minutes</td>
</tr>
<tr>
<td>Malfunctions</td>
<td><input type="number" name="Malfunctions" placeholder=""> minutes</td>
</tr>
<tr>
<td>Theoretical production time:</td>
<td><p id="test"></p></td>
</tr>
</table>
<input type="button" onclick="Calculate()" name="Calculate" value="calculate">
<script>
function Calculate()
{
var TotalProductionTime = document.getElementById("TotalProductionTime").value;
var TotalProductionTimeInMinutes = TotalProductionTime * 60;
var Breaks = document.getElementById("Breaks").value;
var Malfunctions = document.getElementById("Malfunctions").value;
var TheoreticalProductionTime = TotalProductionTimeInMinutes - Breaks - Malfunctions;
document.getElementById("test").innerHTML = TheoreticalProductionTime;
}
</script>
</body>
</html>
You had some mistakes in your HTML, but here is a working JSFiddle: Fiddle
You you are trying to get elements by their ID, but you don't give them an ID you give them a Name. Also, stop using inline JavaScript calls; it is bad practice.
function Calculate() {
var TotalProductionTime = document.getElementById("TotalProductionTime").value;
var TotalProductionTimeInMinutes = TotalProductionTime * 60;
var Breaks = document.getElementById("Breaks").value;
var Malfunctions = document.getElementById("Malfunctions").value;
var TheoreticalProductionTime = TotalProductionTimeInMinutes - Breaks - Malfunctions;
document.getElementById("test").innerHTML = TheoreticalProductionTime;
}
<form id="frm1" action="Calculate.html">
<table width="350px" border="1px">
<tr>
<th colspan="2">Availability</th>
</tr>
<tr>
<td>Total Production Time</td>
<td>
<input type="number" id="TotalProductionTime" placeholder="">hours</td>
</tr>
<tr>
<td>Breaks</td>
<td>
<input type="number" id="Breaks" placeholder="">minutes</td>
</tr>
<tr>
<td>Malfunctions</td>
<td>
<input type="number" id="Malfunctions" placeholder="">minutes</td>
</tr>
<tr>
<td>Theoretical production time:</td>
<td>
<p id="test"></p>
</td>
</tr>
</table>
<input type="button" onclick="Calculate()" value="calculate">
</form>
Every id must be converted to integer. Example
var Malfunctions = parseInt(document.getElementById("Malfunctions").value);
then your ready to go
With HTMLInputElement you can use property .valueAsNumber which returns a numeric property if possible:
const str = document.querySelector("input").value;
const num = document.querySelector("input").valueAsNumber;
console.log(typeof str, str, str + 2);
console.log(typeof num, num, num + 2);
<input type="number" value="40" disabled />
You've got two problems here. One obvious is that you try to get a reference to the form inputs by id, but didn't give them any (you gave them a name). To fix, either change the name attribute to an id, or use the form-specific way to reference them, e.g.:
var TotalProductionTime = document.forms.frm1.TotalProductionTime
Second problem is more vicious and has to do with the scope of execution of what you put in onclick attributes. You see, your button is named "Calculate" just like your function, and in the context of the onclick attribute, its parent form is used to resolve identifiers before the global scope. So instead of calling the function named Calculate, you're trying to call the button itself. Fix that by giving them different names, referencing window.Calculate explicitly, or much better, define your event handler in JavaScript instead of using the HTML attribute:
document.forms.frm1.Calculate.onclick=Calculate

Edit a specified cell in a table - jsp

I need some help with javascript/jquery or ajax.
A am writing a java web app and have question regarding table.
I need to have the possibility to edit one (and only one specified cell). In this case I have the "status" field. When clicking on the value I'd like to have a dropdown list with 2 possibilities to choice: "active" and "passive".
I tried to figure it out, but without success.
Here is my code:
<body>
<table border = "1">
<tr>
<td>name</td>
<td>surname</td>
<td>status</td>
</tr>
<tr>
<td> Adam</td>
<td>Smith</td>
<td id = "status" onclick = "update(this.id)">active</td>
</tr>
</table>
<script type = "text/javascript">
function update(id){
var content = document.getElementById(id).firstChild.nodeValue;
document.getElementById(id).innerHTML = "<input type = 'text' name = 'txtNewInput' id = 'txtNewInput' value = '" + content + "'/>";
}
</script>
</body>
In this case when I click on the cell the value changes to "null" and it is not editable anymore.
You want to do something like this:
<td>
<input
type='text'
name='txtNewInput'
id='txtNewInput'
value='<c:out value="${person.status}" />'
onChange='AjaxCallToUpdateDB(this.id, this.value)'
/>
</td>
Actually sending the update to the database when the user makes a change requires more than making this an input: you need an Ajax call to a Servlet to save the value in the database.

Showing total of loaded values

Hi I have form that lists certain values of sales. After loading sales I want to show the total of all the values. Right now it works fine but I have to change some value and it will show the total. What I want to do is also to show the total upon loading the form.
<form id="sales" action="" >
<table class="salesTable" border="1" cellpadding="0" cellspacing="0">
<tbody>
{{#each items}}
<tr class="">
<td><input type="abd" name="{{=id}}" id="{{=id}}" value='{{=sales}}' onchange="updateTotal(this.form)" /></td>
</tr>
<tr>
<td style="font:bold">Total</td>
<td><input type="abd" name="sum" onfocus="this.blur()" readyonly value=""/> </td>
</tr>
</tbody>
</table>
</form>
jquery function is
function updateTotal(formObj) {
var total = 0;
total += parseInt(formObj.s1011.value, 10)
total += parseInt(formObj.s1018.value, 10)
total += parseInt(formObj.s1019.value, 10)
formObj.sum.value = total
}
Please let me know how can i change it so it will also show the total of the values when form is leaded. Thanks
You can call the function when DOM is loaded and ready.
E.g with jQuery:
$(function() { // This is executed when DOM is ready
var form = $("#sales")[0]; // get the form's DOM node
updateTotal(form); // call the function on it
});

Categories