Puppeteer $$evan and QuerySelector - puppeteer

I need to get the code and product's title. I tried this but it returns me 'Cannot read property 'innerText' of null"
HTML
<th data-code="XXXXXX">
<div>
<div id="title"><span>Product title</span></div>
</div>
</th>
<th data-code="XXXXXX">
<div>
<div id="title"><span>Product title</span></div>
</div>
</th>
Puppeeter
let table = await page.$$eval(
'table th',
divs => divs.map((div, index) => ({
title: div.querySelector('#title').innerText,
code: div.dataset.code
})
)
);

Related

Table body disappears when clicking first time on checkbox input

noticed a very strange behaviour from table body - it disappears on the first time when I click on checkboxes. As you will see in the gif, data is fetched successfully without any issues. I'm manipulating it whenever user tries to filter it. Couldn't find anywhere related issues to checkboxes and tables. Thanks for any ideas/advices! Want to mark that there are no errors in console, everything is clean, just inside the tbody gets empty
gif
<aside class="last-updates">
<div>
<span>Last 10 minutes update</span>
<div class="checkboxes">
<input type="checkbox" id="available" value="Available" v-model="needToFilter" #click="filterRoutes = true" />
<label for="available">Available</label>
<input type="checkbox" id="in-progress" value="In progress" v-model="needToFilter" #click="filterRoutes = true" />
<label for="in-progress">In progress</label>
<input type="checkbox" id="completed" value="Completed" v-model="needToFilter" #click="filterRoutes = true" />
<label for="completed">Completed</label>
</div>
</div>
<table class="table">
<thead>
<tr>
<th scope="col">Driver ID</th>
<th scope="col">Route</th>
<th scope="col">Latitude</th>
<th scope="col">Longitude</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody v-if="routes">
<tr v-for="route in filteredRoutes" :key="route">
<th>
{{ route.driver_id }}
</th>
<th>
{{ route.route_name ? route.route_name : 'No data' }}
</th>
<th>
{{ route.route_latitude }}
</th>
<th>
{{ route.route_longitude }}
</th>
<th
:class="
route.route_status === 'Available'
? 'not-driving'
: route.route_status === 'In progress'
? 'in-progress'
: 'completed'
"
>
{{ route.route_status }}
</th>
</tr>
</tbody>
<tbody v-else>
<p>Fetching data from database...</p>
</tbody>
</table>
</aside>
<script>
import { ref, computed } from 'vue';
import getAllRoutes from '../../composables/routes/getAllRoutes';
export default {
async setup() {
let routes = ref([]);
let needToFilter = ref([]);
let filterRoutes = ref(false);
routes = await getAllRoutes();
const filteredRoutes = computed(() => {
console.log(routes);
if (filterRoutes.value) {
if (needToFilter.value.length === 1) {
return routes.filter(route => route.route_status.startsWith(needToFilter.value[0]));
} else if (needToFilter.value.length > 1) {
for (let i = 0; i < needToFilter.value.length; i++) {
// todo
}
}
} else {
// Default sorting, displayed when page is loaded
const sortingDefaultPriority = ['Available', 'In progress', 'Completed'];
return routes.sort((a, b) => sortingDefaultPriority.indexOf(a.route_status) - sortingDefaultPriority.indexOf(b.route_status));
}
});
return { routes, needToFilter, filteredRoutes, filterRoutes };
}
};
</script>
The issue was with #click. For some reasons whenever I click the checkbox it removes the content from tbody tag. Removing the #click helped me out, found another way to watch the click.

angular fake API using jasonplaceholder, getting details after clicking button

I am working on a dummy API with jsonplaceholder, I am getting all posts after clicking button, but i wanna get userid and title on load,and after clicking title need to get that particular body of that id How can i achieve this.
in jasonplaceholder there are 100 posts with id,title,body. on clicking getdata i need only id and title after when I click on title I need to get body as either in paragraph or popup or something.
html
<button (click)="get()">Get Data</button>
<div class="col-md mt-4 mb-4">
<table class="table table-bordered">
<thead>
<tr>
<th>id</th>
<th>title</th>
<th>body</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let d of data">
<td><span>{{d.id}}</span></td>
<td><span>{{d.title}}</span></td>
<td><span>{{d.body}}</span></td>
</tr>
</tbody>
</table>
</div>
ts
get(){
this.userservice.getData().subscribe((data) =>{
console.log(data)
this.data = data
})
}
service
getData():Observable<any>{
const url = "https://jsonplaceholder.typicode.com/posts";
return this.http.get(url)
}
A simple solution would be to use *ngIf and a variable, eg. selectedId
<td (click)="showBody(d.id)"><span>{{d.title}}</span></td>
<td *ngIf="selectedId === d.id"><span>{{d.body}}</span></td>
Then in your component, initiate it:
selectedId: any = null;
and
showBody(id: number){
this.selectedId ? this.selectedId = null : this.selectedId = id;
}
so that it would hide the body if you click on the title again.
As I understand, you need to get the id of the element you clicked on it to show the element's body.
so to achive this, you can write something like this:
component.html
<tr *ngFor="let d of data" (click)="setBody(d)">
<td><span>{{d.id}}</span></td>
<td><span>{{d.title}}</span></td>
</tr>
<!-- Show selected item body here -->
<h1>Selected item body</h1>
<p>{{selectedItemBody}}</p>
component.ts file
[Optional]: you can define the POST interface top of your ts file to have more clean code:
interface POST {
id: number;
title: string;
body: string;
}
setBody(post: POST) {
this.selectedItemBody = post.body;
alert(this.selectedItemBody); // you can remove this alert
}
I provided you this sample working code here in stackblits

Why are the form inputs in my html table unclickable?

I am trying to render a table in html that is the representation of a reactive form array.
I loop over the complex object (FormGroup > FormArray > FormGroup > FormArray) With the final array being the data that we want to represent to the UI in its transformed format. (Happens in the function groupFormGroup())
Everything works fine, the data is correctly transformed and displayed.
However, now I am trying to add inputs (NOT formControlName inputs) to the table and when they load, they load without me being able to click into, or change their value. They are not disabled, just unclickable. No errors come up in the console.
What I have tried:
Modifying the class names so it is no longer class='form-control'
Increasing the z-index of inputs to be on the forefront
Making the inputs position relative
Here is the code:
<div class="row" [formGroup]="address">
<div class="col-12">
<table class="w-100">
<thead>
<th></th>
<th>Order ID</th>
<th>GP Code</th>
<th>Product</th>
<th>Quantity</th>
<th>Preset Suite Number</th>
<th></th>
</thead>
<tbody>
<ng-template formArrayName="addressOrders" ngFor let-addressOrder [ngForOf]="address.get('addressOrders').controls" let-ao="index">
<ng-container [formGroup]="addressOrder">
<ng-template ngFor let-fulfillment [ngForOf]="groupFormGroup(addressOrder.get('fulfillments').getRawValue(),'orderDetailId')" let-f="index">
<tr>
<td class='table-input'>
<input type="checkbox"
(change)="updateFulfillmentFormControl(fulfillment,addressOrder,'selected',$event)"/>
</td>
<td>{{addressOrder.get('orderId').value}}</td>
<td>{{fulfillment['gpItemNumber']}}</td>
<td>{{fulfillment['name']}}</td>
<td>{{fulfillment['quantity']}}</td>
<td>
<ng-container *ngIf="fulfillment['isSuite']">
<!-- <input class="form-control" (keydown)="updateFulfillmentFormControl(fulfillment,addressOrder,'suiteNumber',$event)" /> -->
<input type="text" class="form-control" />
</ng-container>
</td>
<td>Edit Detail</td>
</tr>
</ng-template>
</ng-container>
</ng-template>
</tbody>
</table>
</div>
</div>
And the code generating the Form Group:
draw() {
this.formGroup = this.initFormGroup(this.ordersToDisplay)
}
initFormGroup(ordersToDisplay: Array<BulkFulfillCustomer>):FormGroup {
var queueList = this.queues.map(q => q['queue_id']);
return this.fb.group({
customers: this.fb.array(
ordersToDisplay.map(otd => {
return this.fb.group({
gpCustomerNumber:[otd.gpCustomerNumber],
customerName:[otd.customerName],
customerAddresses: this.initAddressForm(otd.addressOrders, queueList)
})
})
)
})
}
initAddressForm(addressOrders: Array<BulkFulfillAddress>, queues:Array<string>):FormArray {
return this.fb.array(
addressOrders.map(ao => {
return this.fb.group({
addressLine:[ao.addressLine],
bundleShipment:[true],
addressOrders: this.initAddressOrdersForm(ao.orders,queues)
})
})
)
}
initAddressOrdersForm(orders: Array<BulkFulfillOrder>, queues:Array<string>):FormArray {
return this.fb.array(
orders.map(o => {
return this.fb.group({
orderId: [o.order.id],
fulfillments: this.initFulfillmentsForm(o.orderDetailFulfillments,queues)
})
})
)
}
initFulfillmentsForm(fulfillments: Array<FulfillmentLine>, queues:Array<string>) {
return this.fb.array(
fulfillments.map(f => {
return this.fb.group({
selected:[true],
expandDetail:[false],
isSuite:[f.inventory.isSuite],
suitePrefix:[f.inventory.suitePrefix],
gpItemNumber:[f.inventory.gpItemNumber],
name:[f.inventory.name],
queueId:[{value:f.inventory.pulseQueueId,disabled:(!this.isPulseFulfill && f.inventory.fulfillmentMethod != INVENTORY_FULFILLMENT_PULSE)}, Validators.compose([Validators.required, ContainsListValidator(queues,'Queue ID')])],
orderDetailId:[f.orderDetailFulfillment.orderDetailId],
pulseOrderId:[f.orderDetailFulfillment.pulseOrderId],
suiteNumber:[{value:f.orderDetailFulfillment.suiteNumber,disabled:!this.isPulseFulfill || !f.inventory.isSuite}, Validators.required],
quantity:[{value:f.orderDetailFulfillment.quantity,disabled:f.orderDetailFulfillment.fulfillmentMethod != 1},Validators.compose([Validators.required, Validators.min(1),Validators.max(f.orderDetailFulfillment.quantity)])]
})
})
)
}

Angular determine style based off conditional

I am trying to change the row of a table to #0093ff; if the Holidays.HolidayDate is the next upcoming holiday.
NEW CODE:
<table ng-if="model.Holidays" class="table">
<tr>
<th>Holiday</th>
<th>Date</th>
<th>Branch</th>
<th>Hours</th>
</tr>
<tr ng-repeat="Holidays in model.Holidays" ng-style="isUpcomingHoliday(Holidays.HolidayDate) ? 'color:#0093ff' : '' ">
<td>{{Holidays.HolidayName}}</td>
<td>{{Holidays.HolidayDate | fulldaydate}}</td>
<td>{{Holidays.Branch ? Holidays.Branch : 'All'}}</td>
<td>{{Holidays.Hours ? Holidays.Hours : 'Closed'}}</td>
</tr>
</table>
JS
.filter('isUpcomingHoliday', ['$filter',
function ($filter) {
return function (input) {
const sortedHolidays = this.model.Holidays.sort((a, b) => {
return moment(b.date).isAfter(moment(a.date))
});
const upcomingHoliday = sortedHolidays[0];
return moment(holidayDate).isSame(upcomingHoliday);
};
}])
You can achieve it by sorting holidays and compare with the first element. I think it can look like this:
isUpcomingHoliday(holidayDate) {
const sortedHolidays = this.model.Holidays.sort((a, b) => {
return new Date(b.HolidayDate) - new Date(a.HolidayDate)
};
return holidayDate.getTime() === sortedHolidays[0].getTime();
}
<section class="module module-divider-bottom" data-app="global">
<div class="container" ng-controller="ContactController">
<div class="container">
<table ng-if="model.Holidays" class="table">
<tr>
<th>Holiday</th>
<th>Date</th>
<th>Branch</th>
<th>Hours</th>
</tr>
<tr ng-repeat="Holidays in model.Holidays" ng-style="isUpcomingHoliday(Holidays.HolidayDate) ? 'background-color:#0093ff' : '' ">
<td>{{Holidays.HolidayName}}</td>
<td>{{Holidays.HolidayDate | fulldaydate}}</td>
<td>{{Holidays.Branch ? Holidays.Branch : 'All'}}</td>
<td>{{Holidays.Hours ? Holidays.Hours : 'Closed'}}</td>
</tr>
</table>
</div>
</div>
</section>
It could be better and more readable with moment.js:
isUpcomingHoliday(holidayDate) {
const sortedHolidays = this.model.Holidays.sort((a, b) => {
return moment(b.date).isAfter(moment(a.date))
};
const upcomingHoliday = sortedHolidays[0];
return moment(holidayDate).isSame(upcomingHoliday);
}
Something like this should do the trick. I didn't know if you already had an api that tells you the next holiday, If you are using moment to check if the date is the same (or if you already have something to compare dates).
I chose the class vs ngStyle because you might want to style other things related to that holiday. Hope that helps.
isNextHoliday (holidayDate): boolean {
// return some function that compares the two dates
}
.some-color {
background: red;
}
<section class="module module-divider-bottom" data-app="global">
<div class="container" ng-controller="ContactController">
<div class="container">
<table ng-if="model.Holidays" class="table">
<tr>
<th>Holiday</th>
<th>Date</th>
<th>Branch</th>
<th>Hours</th>
</tr>
<tr ng-repeat="Holidays in model.Holidays">
<td>{{Holidays.HolidayName}}</td>
<td [class.some-color]="isNextHoliday(Holidays.HolidayDate)">{{Holidays.HolidayDate | fulldaydate}}</td>
<td>{{Holidays.Branch ? Holidays.Branch : 'All'}}</td>
<td>{{Holidays.Hours ? Holidays.Hours : 'Closed'}}</td>
</tr>
</table>
</div>
</div>
</section>

Delete last row of table in nested div

i want to delete last row.
i have dive within div , which has table and many rows.
i wanted to delete last row of table. i am unable to iterate to last tr.
<div class="span15" id="MURWorksheetPage2">
<div class="span8">
<table>
<tr>
<td class="col1">
#Html.DisplayNameFor(model => model.MedicineUseNo) #Html.TextBoxFor(model => model.MedicineUseNo, new { id = "txtMedicineUseNo", style = "Width:20px" })
</td>
<td class="col2">#Html.DisplayNameFor(model => model.MedicinePrescribed) #Html.TextBoxFor(model => model.MedicinePrescribed, new { id = "txtMedicinePrescribed" })</td>
</tr>
<tr>
<td class="col1" colspan="2">
#Html.DisplayNameFor(model => model.OTC) #Html.TextBoxFor(model => model.OTC, new { id = "txtOTC" })
</td>
</tr>
</table>
</div>
</div>
Not tested, but this should work.
$('#MURWorksheetPage2 div table :last').remove();