How to select a drop down menu option in Puppeteer bot? - puppeteer

I am trying to customise a Puppeteer bot which fills out a reservation form, searches for an available date and if it’s not available it refreshes the page. The bot only selects some options but I’d like to add more. Currently it leaves the default “1” room in the drop down menu but I’d like to select “2”.
Below is the current code and I’d like to select 2 for no_of_rooms
async function prepareAndCheckPage(){
//select 2 rooms
await page.select('#form_no_of_rooms', '2'); //this code doesn't work
//accessibility requirement – this code correctly selects the second radio button
await page.waitForSelector('#form_rooms_0_accessibilityRequirement_1');
const accessibilityRequirement = false;
page.$eval('#form_rooms_0_accessibilityRequirement_' + (accessibilityRequirement ? 0 : 1), elem => {
elem.checked = true;
});
Here is the HTML from the page
<div id="accommodation-add-rooms">
<div class="row / mb-6">
<div class="col-md-7">
<div class="form-group mb-0"><label class="required" for="form_no_of_rooms">Preferred number of rooms*</label><div id="form_no_of_rooms_help" class="d-block / mb-1">Please note your preferred number of rooms and room configuration are not guaranteed.</div><select id="form_no_of_rooms" name="form[no_of_rooms]" class="col-12 col-md-2 form-control" aria-describedby="form_no_of_rooms_help"><option value="1">
1
</option><option value="2">
2
</option></select>
Obviously I'm very inexperienced in this. What am I doing wrong? I’ve tried both form_no_of_rooms and no_of_rooms

Related

How do I improve performance when constructing a grid in Angular?

Everytime the route changes (recordTab.Id changes) I have to construct a new grid with five columns and output it.
The following code generates the grid every route change
// used later in html code to generate five columns with *ngFor
this.columns = [0,1,2,3,4]
// the records are filtered based on the id
this.id = recordTab["id"];
//allRecords has 1300 elements in it
this.records= allRecords.filter(record => record.recordTabId == this.id); // filter by recordTabId
// construct grid with 5 columns
// the maximum number of cells per column are 300
for(let i=0; i<5; i++){
this.grid[i] = [];
this.grid[i] = new Array(recordTab["gridCells"]); // number of cells in a column
}
if(this.records){
for(let record of this.records){
// assigning record to its corresponding cell
this.grid[record.column - 1][record.row - 1] = record;
}
}
// has maximum 5*300 entries
// 600 entries filled
// rest is empty to simulate empty cells
console.log(this.grid)
Now I am displaying the grid in the following way:
<div class="grid-container">
<div class="column" *ngFor="let column of columns">
<div class="cell" *ngFor="let record of grid[column]">
<ng-container *ngIf="record">
<div class="record checkboxes" [ngStyle]="{'background-color': record.categorie==1 ? record.rgbFarbeHex : 'white'}" [ngClass]="{'heading-container': record.categorie==1}">
<label [ngClass]="{'heading': record.categorie==1}" [title]="record.name" (contextmenu)="showRecordInformation($event, record)"> <span *ngIf="record.categorie==0"> <input type="checkbox"> </span> {{record.name}}</label>
</div>
</ng-container>
</div>
</div>
</div>
The problem is that the grid takes some time to show up for the grid with 5*300 entries and 600 actually filled entries. How could I improve the performance?
I dont think the css is the problem, that is why I dont show it. If it is necessary, tell me.
You should take a look at trackBy. It will tell your ngFor to only rerender what changed based on what you are tracking. It's hard to tell if it can work in your case but there is no other solution since as soon as the array changes, angular loose track of what's going on and needs to render the *ngFor again.
It would look like that:
<div class="column" *ngFor="let column of columns; trackBy:trackByFn">
trackByFn(index, item) {
return item.id;
}

Select inside ng-repeat with ng-options and ng-model

Good Morning,
Hope everyone had a great Easter,
Before I begin, I want to point out this is being developed in ServiceNow Orlando release, it uses AngularJS 1.6.10
I'm stuck on a tricky piece of code I can't get right, I'm using an ng-repeat to build out a catalog of hardware devices, in this case its Laptops, we have added a button which quickly allows people to add the device to the cart, we now want to add a quantity field so that multiple devices can be added at the same time, I got it working but AngularJS adds in an empty cell at the beginning, I need to get it to default to 1, I did get it to do this but it broke the cart experience as every item added to the cart is a 1 no matter what quantity is selected.
so this is most of the html code which also includes the ng-repeat that builds out the hardware devices, I am using an ng-options that everyone seems to recommend, been reading a lot in Stack Overflow.
The problem is the ng-model, as this is set to $scope.items[0] it never gets updated, I have been looking at getterSetter but very much going over my head at the moment, can't get it to work.
<div class="col-sm-6 col-md-4 funky-show-hide" ng-show="selectedCat==item.categoryBelongTo" ng-repeat="item in data.items track by $index">
<div class="panel panel- b" >
<a target="" ng-href="" ng-click="onClick($event, item)" class="panel-body block">
<div class="overflow-100">
<h4 class="m-t-none m-b-xs hrline"><span ng-if="item.content_type == 'external'"> <i ng-if="data.isDownloadable.indexOf(item.sys_id) ==-1" class="fa fa-external-link-square" aria-hidden="true" style="color: #498fcc;"></i><i ng-if="data.isDownloadable.indexOf(item.sys_id) >-1" class="fa fa-download" aria-hidden="true" style="color: #498fcc;"></i></span></h4>
<img ng-src="" ng-if="item.picture" class="m-r-sm m-b-sm item-image pull-left" />
<div class="text-muted item-short-desc"></div>
</div>
</a>
<div class="panel-footer" >
<span ng-if="item.u_show_price == 'true'" class="pull-right item-price font-bold"></span>
<button ng-if="item.u_show_add_to_cart_button == 'true' " name="submit" ng-disabled="submitted" ng-click="triggerAddToCart(item.sys_id, selected.label)" class="btn btn-primary">${Add to Cart}</button>
<select ng-if="item.u_show_quantity_button == 'true'"
name="Quantity"
id="quantity"
ng-disabled="submitted"
ng-model="selected"
class="form-control quantity-selector"
data-toggle="tooltip"
tooltip-top="true"
data-original-title="${Quantity}"
ng-options="item as item.label for item in items track by item.id">
</select>
</div>
</div>
</div>
Controller:
$scope.items = [{
id: 1,
label: '1'
}, {
id: 2,
label: '2'
}, {
id: 3,
label: '3'
}];
$scope.selected = $scope.items[0];
What it all looks like:
So I have selected "3" on the Performance PC Laptop but if you look at the console log on the right, you can see the value added is 1.
Picture to display value added to cart
Shame really, I was happy with the empty cell but its what the client would like, I know I can update the empty cell with some text but they would really like it to default to 1.
Any suggests and I would be grateful,
Bored Panda
Replacing the ng-if with ng-show resolved my problem, days lost trying to figure this out, also developed a simpler solution with number increment
Code Here:
<input type="number" value="1" min="1" max="20" step="1" ng-model="items_increment" title="Quantity" ng-show="item.u_show_quantity_button == 'true'"/>
$scope.items_increment = 1;
Hope it helps another person.

Update table cell value dynamically using angular6

I am working with an angular 6 application, in the HTML template I have some code as per below, just showing the table cell part of the array, also the table is built using divs.
<div class='table_small'>
<div class='table_cell'>Status</div>
<div class='table_cell'>
<p class="status" >{{incomingData.status}}</p>
</div>
</div>
Please note here that "data" is an array (*ngFor) and is being used in row data and there are multiple data in the table.
Now I have a situation wherein there is a button inside the table rows to cancel the particular order, when the user clicks in, a pop up/modal asks for user confirmation, if the user opts for 'Yes' it would change the status field value to "cancellation is in process" temporarily before it hits the service, once there is a successful response from the customer it would change the station to "cancelled".
I am really not sure how to do the cancellation within the table cell here, if anyone can give insight on this please do.
Thanks
You could pass the element to the function and edit its status:
<div class='table_small'>
<div class='table_cell'>Status</div>
<div class='table_cell'>
<p class="status" >{{incomingData.status}}</p>
</div>
<div class='table_cell'>
<button (click)="showCancelModal(incomingData)"> Cancel</p>
</div>
</div>
And then in the component something like this:
showCancelModal(incomingData) {
// logic for showing modal and retrieving user response
if( response === 'yes') {
incomingData.status = 'Cancel in progress';
yourService.cancel(incomingData)
.pipe( finally(() => incomingData.status = 'Cancelled') )
.subscribe();
}
}

How to run website forms in Excel without having to use Sendkeys?

I am trying fill out a form on a website using Excel VBA. I have created an InternetExplorer.Application, navigated to the page and looked up a bunch of data, using If UserForm1.TC2.Value = True Then or something like PostCode = objIE.document.getElementsByName("ProjectFile-ProposalAddress-PostCode")(0).Value and the like.
Afterwards, I navigate to a new page, and look to fill it out using my previous data.
And this is where I run into trouble. I want to tick a check box 'New Permit', and its code is;
<form id="document-form">
<div class="generate-form form-horizontal">
<div class="form-group"><label class="col-sm-3 control-label"><span>New Permit</span></label><div class="input col-sm-7">
<div class="checkbox">
<input type="checkbox" data-bind="checked: NewPermit" />
</div></div></div><div class="form-group"><label class="col-sm-3 control-label"><span>Staged Permit</span></label><div class="input col-sm-7">
<div class="checkbox">
<input type="checkbox" data-bind="checked: StagedPermit" />
</div>
Which has no name to lock into. I'm not a HTML expert, but there is some more code that refers to this tickbox (I think)
var model = { "NewPermit": null, "StagedPermit": null, "AmendedPermit": null,
etc.
I have run a loop through the code using .getElementsByTagName("Span") with various .tagName etc. The following results is for the New Permit box:
.tagName = Span
.outerHTML = New Permit
.outerText = .innerHTML = .innertext = New Permit
.isContentEditable = False
.tostring = [object HTMLSpanElement]
.ID = ""
This is behind a password log in, and I cannot post the link publicly. But can work through PM etc to get to the answer.
Use getElementsByTagName('input') and then use Checked = True
Dim element as Object
element = getElementsByTagName('input')
element.Checked = True
assumes checkbox is the only input element on the page. If not, make a loop and identify the desired checkbox

Form with select and text options

I have an HTML form that needs to collect information entered into a text box as well as options that are chosen from a set of dropdown menus. To give a little context, I am creating virtual machines that can be configured by the user on a web page. They must enter a name (arbitrary) and a hostmachine in two separate boxes in addition to selecting options from three different dropdown menus. Because I am working with clusters, there could be as many as 99 "rows" of dropdown menus representing different system configurations that will be a part of the cluster.
Is it possible (if so, advisable?) to have both the text fields and the dropdowns contained in one form? If not, how do I make sure that the submit button sends all the data to my Django server for processing as I need all of this information to ultimately come to the same place.
I currently have them in different forms, but just ignore this for now as it doesn't do anything at the moment. Also don't worry about the lack of dropdowns present in this code as the addSelect() JS function is fully functional. Just know that each added node is given a unique name (node1, node2, etc.) and goes into the div "nodes".
<body><b>Virtual Cluster Initialization</b><br></br>
<div id="container">
<div id="general">
<form method="POST" id="naming">Cluster name:<br>
<input type="text" name="cluster_name">
<br>
Host Machine:<br>
<input type="text" name="host_machine">
</form>
</div>
<form method="POST" id="node_config"></form>
<div id="nodes" form="node_config"></div>
<div id=node1">
<select name="node_type" id="node_type">Node Type</option>
(two options go here)
<select name="issp_version" id="issp_version>ISSP Version</option>
(7 or so options go here)
<select name="os" id="os">Operating System </option>
(about 20 options)
<button id="add" onclick="addSelect('nodes');">+</button>
</div>
<br></br><input type="submit"></input>
</body>
EDIT1: Added the an example dropdown for clarity. Would it be better to NOT make a new div for each node? I did this initially because it seemed like a good way to keep each node's configuration separate. Like I said, there could be up to 99 nodes, each with three dropdown menus.
Not really sure if I understand what you're asking. Showing us the code after your drop downs are added would help. Syntax wise, this wont work. Inputs should be inside forms and div doesn't have a form property.
Put everything into one form if you want it to all be in one post. If your dynamically adding new form elements you can use an array as element names.
How about something like this?
<script>
var nodeID = 0;
function addSelect() {
var html = "<div id='node_" + nodeID + "'>";
html += "<select name='node_type[" + nodeID + "]' id='node_type'><option>example</option></select>";
html += "<select name='issp_version[" + nodeID + "]' id='issp_version'><option>ISSP Version</option></select>";
html += "<select name='os[" + nodeID + "]' id='os'><option>Operating System </option></select>";
html += "</div>";
document.getElementById('nodes').innerHTML += html;
nodeID++;
}
</script>
<div style="margin-bottom:20px;"><b>Virtual Cluster Initialization</b>
</div>
<form>
<div id="container">
<div id="general">
<div>Cluster name:</div>
<div>
<input name="cluster_name" type="text">
</div>
<div>Host Machine:</div>
<div>
<input name="host_machine" type="text">
</div>
</div>
<div id="nodes">
<div>Nodes</div>
<div id="node_0">
<select name="node_type[0]" id="node_type"><option>example</option></select>
<select name="issp_version[0]" id="issp_version"><option>ISSP Version</option></select>
<select name="os[0]" id="os"><option>Operating System </option></select>
</div>
<div id="node_1">
<select name="node_type[1]" id="node_type"><option>example</option></select>
<select name="issp_version[1]" id="issp_version"><option>ISSP Version</option></select>
<select name="os[1]" id="os"><option>Operating System </option></select>
</div>
</div>
<div>
<button type="button" id="add" onclick="addSelect();">+</button>
</div>
</div>
<div>
<input type="submit">
</div>
</form>
Here is a JSfiddle to help you visualize what this does:
https://jsfiddle.net/fdss08w9/2/
Example of how you might use this in Django:
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# Get the number of nodes we added
for id, node_type in enumerate(form.cleaned_data['node_type']):
issp_version = form.cleaned_data['issp_version'][id]
os = form.cleaned_data['os'][id]
#do stuff with node_type, issp_version, os