puppeteer pick a date from the calendar by class name if available - node.js

what i want: if there is a green date click on it (the first one or the last), if not keep reloading
you can see the calendar image below
note: the green date has always a class name "activeClass" + title="Book"
const rdvLoop = async () => {
await page.waitForTimeout(1000)
await page.reload()
await page.waitForTimeout(1000)
if ((await page.$("td.activeClass")) !== null ){
await page.waitForSelector('td.activeClass:nth-child(1)')
await page.click("td.activeClass:nth-child(1)")
await page.waitForTimeout(1000)
}
if ((await page.$("td.activeClass")) == null ){
await page.waitForTimeout(1000)
await page.reload()
}
}
rdvLoop()
for (var i = 0; i = 10 ;i++) {
await page.waitForTimeout(1000)
await rdvLoop()
}
this is the website calendar (minimalized)
<div class="datepicker datepicker-dropdown dropdown-menu" >
<div class="datepicker-days" >
<table class=" table-condensed">
<tbody>
<tr>
<td class="day disabled fullcap" title="Slots Full">8</td>
<td class="day disabled fullcap" title="Slots Full">9</td>
<td class="active day disabled fullcap" title="Slots Full">10</td>
<td class="disabled day activeClass" title="Book">11</td>
</tbody>
</table>
</div>
</div>
here is the calendar image from the website

Related

How i can update my todo status using checkbox in mean stack if check box is checked it place true in mongodb database otherwise false

app.component.ts
Debugger given the error that this.task is undefined
updateTodo(task: any){
this.todoService.updateData(task._id, this.task).subscribe(res => {
this.data= res;
console.log(res);
console.log(this.task);
});
}
app.service.ts
This is service file where the backend api are call in my angular app
updateData(id: any , data: any){
return this.httpClient.put('http://localhost:3000/todos/'+id, data);
}
app.component.html
This is the frontend of my app where the todos show and others user interface
<tbody>
<tr *ngFor="let todo of tasks ; let i = index">
<td>{{todo.todos}}</td>
<td> <input type="checkbox" (change)="updateTodo(todo)"[checked]="todo.isDone</td>
<td>
<button class="btn btn-danger btn-sm" id="del-btn"
(click)="deleteData(todo._id)">Delete</button>
</td>
</tr>
</tbody>
app.model.ts
This is model file
export class Todo {
_id:any;
todos:any;
isDone:any;
}
backend api
This is the backedn function which i created to update my todo
router.put('/:id' , async (req,res) => {
const id = req.params.id;
if(ObjectId.isValid(id)){
const todo = (req.body);
const todoUpdate = await Todo.findByIdAndUpdate(id ,{$set:emp}, {new:true});
res.status(200).json({code:200, message:'Todo Updated Successfully'});
}
else{
res.status(400).send('Todo Not Found By Given Id' + id);
}
});
I'm not sure if we understood each other, but you are passing the task as a parameter but then on two occasions you are trying to use the value of this.task. They are not the same thing and if this.task is not initialized then of course it will show that it's undefined.
updateTodo(task: any) {
console.log('task:', task); // Is the task correct?
this.todoService.updateData(task._id, task).subscribe(res => {
this.data = res;
console.log(res);
console.log(task); //not this.task
});
}
EDIT:
If the DB is not updated you might be sending incorrect data there. If there are no errors on Angular side you have to check the Back-End side.
I solve this question to add [(ngModel)]="todo.isDone" in my checkbox input filed
<tbody>
<tr *ngFor="let todo of tasks ; let i = index">
<td>{{todo.todos}}</td>
<td> <input type="checkbox" (change)="updateTodo(todo)" [(ngModel)]="todo.isDone</td>
<td>
<button class="btn btn-danger btn-sm" id="del-btn"
(click)="deleteData(todo._id)">Delete</button>
</td>
</tr>
And In my app.component.ts
updateTodo(task: any) {
this.todoService.updateData(task._id, task).subscribe(res => {
this.data = res;
console.log(res);
console.log(task);
});
}

Having hard time scraping a cell with Cheerio

I'm trying to scrape a cell from a table but I'm having a hard time and I'm probably doing something wrong because I get an empty result in the console(literally nothing).
Here's the HTML:
I'm trying to get the <td class="center bold storing_1">1</td>.
Here's my code:
const rp = require('request-promise');
const cheerio = require('cheerio');
const url = 'MY URL';
rp(url)
.then(function(html) {
$ = cheerio.load(body);
console.log($('#table_results tbody tr:nth-child(1) td.center.bold.sorting_1')).text();
})
.catch(function(err) {
});
Any help is appreciated! Thanks!
I think your code is actually ok, I think you just have a few typos in it.
You are parsing 'body' rather than 'html'
You are reading .text() from the result of console.log() rather than the cheerio object ($).
If you try the code below it should work:
const rp = require('request-promise');
const cheerio = require('cheerio');
const url = 'MY URL';
rp(url).then(function(html) {
$ = cheerio.load(html);
console.log("Result:", $('#table_results tbody tr:nth-child(1) td.center.bold.sorting_1').text());
})
.catch(function(err) {
console.error("An error occurred:", err);
});
Html I'm testing with:
Test html
<table id="table_results">
<thead></thead>
<tbody>
<tr ajax-controller="community">
<td class="center bold sorting_1">1</td>
<td class="center bold sorting_1">2</td>
</tr>
</tbody>
</table>
Simple test setup:
You can play around with this to see how editing the selector changes things:
const testHtml =
`<table id="table_results">
<thead></thead>
<tbody>
<tr ajax-controller="community">
<td class="center bold sorting_1">1</td>
</tr>
</tbody>
</table>`;
$ = cheerio.load(testHtml);
console.log("Result:", $('#table_results tbody tr:nth-child(1) td.center.bold.sorting_1').text());

Formatting data in with Cheerio

I want to get the list of IP from a website and add them into an array. The website shows the data like this:
<tbody><tr role="row" class="odd">
<td>131.108.216.44</td>
<td>47267</td>
<td>BR</td>
<td class="hm">Brazil</td>
<td>elite proxy</td>
<td class="hm">no</td>
<td class="hx">yes</td>
<td class="hm">2 minutes ago</td>
</tr>
<tr role="row" class="even">
<td>85.173.165.36</td>
<td>46330</td>
<td>RU</td>
<td class="hm">Russian Federation</td>
<td>elite proxy</td>
<td class="hm">no</td>
<td class="hx">yes</td>
<td class="hm">2 minutes ago</td>
</tr>
</tbody>
This is actually a very long list with 100's of table but the format is the same.
What I did is :
var c = new Crawler({
maxConnections: 1,
callback: function (error, res, done) {
if (error) {
console.log(error)
} else {
var $ = res.$;
$('tbody>tr>td').each((i, el) => {
const item = $(el)
console.log(item.text());
})
}
done();
}
})
c.queue({
uri: 'https://free-proxy-list.net/'
})
I want to keep the first 10 IPs from the website and add them into an array.
The first 10 would look like this:
let proxies = $('tr[role=row]').map((i, tr) => {
let host = $(tr).find('td:nth-child(1)').text()
let port = $(tr).find('td:nth-child(2)').text()
return `${host}:${port}`
}).get().slice(0, 10)

In React how to create input fields and change current items in a row?

I have a parent and a child components. There creates a table with data. I have a modify icon in every row of a table. Now I need when this icon is clicked - there were created input fields for this particular row and this data can be modified, then if pressed "Ok" - pass this changed data to database with "axios.put" method, and if pressed "cancel" - do note modify item.
I created isInEditMode variable. But I don't know where to create that input fields, in child or in parent?
Child:
import React from 'react';
import './tableHasp.css';
class TableHasp extends React.Component {
render(){
return (
<tr>
<td>{ this.props.hasps._id}</td>
<td>{ this.props.hasps.serial }</td>
<td>{ this.props.hasps.soft }</td>
<td>{ this.props.hasps.numberOfKeys }</td>
<td>{ this.props.hasps.company.name }</td>
<td>{ this.props.hasps.company.city }</td>
<td>{ this.props.hasps.company.phone }</td>
<td>{ this.props.hasps.dateCreated }</td>
<td><i onClick={() => this.props.modifyEvent(this.props.hasps)} className="far fa-edit btnEdit"></i></td>
<td><i onClick={() => this.props.delEvent(this.props.hasps._id)} className="far fa-trash-alt btnDelete" ></i></td>
</tr>
);
}
}
export default TableHasp;
Parent data for child:
<div className="container">
<table className="table table-striped">
<thead className="thead-dark">
<tr>
<th scope="col">id</th>
<th scope="col">Serial Number</th>
<th scope="col">Soft</th>
<th scope="col">Number of Keys</th>
<th scope="col">Company</th>
<th scope="col">City</th>
<th scope="col">Contacts</th>
<th scope="col">Date Created</th>
<th scope="col">Edit</th>
<th scope="col">Delete</th>
</tr>
</thead>
<tbody>
{this.state.hasps.map((hasp, i) =>
<TableHasp
delEvent={(hasp) => this.deleteCurrentHaspInfo(hasp)}
modifyEvent={(id) => this.modifyCurrentHaspInfo(id)}
key={i}
hasps={hasp}
/>)}
</tbody>
</table>
</div>
Function that will modify item data:
modifyCurrentHaspInfo = (hasp) => {
this.setState({
isInEditMode: !this.state.isInEditMode,
editHasp: hasp
})
console.log(hasp);
// if (prompt("Enter password:") === "123456") {
axios.put("/hasp/change",
{
_id: hasp._id,
serial: "yyyyy-99000", //test data
soft: "test-put3" //test data
}
)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
})
// } else {
// alert("Wrong password!");
// }
}
Send the index instead of the object
<td><i onClick={() => this.props.modifyEvent(i)} className="far fa-edit btnEdit"></i></td>
Modify the value, and add the prop in item.
modifyCurrentHaspInfo = (index) => {
const hasps = [...this.state.hasps];
hasps[index].isInEditMode = true;
this.setState({hasps});
console.log(hasp);
// if (prompt("Enter password:") === "123456") {
axios.put("/hasp/change",
{
_id: hasp._id,
serial: "yyyyy-99000", //test data
soft: "test-put3" //test data
}
)
.then((res) => {
console.log(res.data);
})
.catch((err) => {
console.log(err);
})
// } else {
// alert("Wrong password!");
// }
}
Create a new with the condition.
{this.props.hasps.isInEditMode && <td>ACTION!!!</td>}
IMPORTANT
Do not use INDEX as a key
{this.state.hasps.map((hasp, i) =>
<TableHasp
delEvent={(hasp) => this.deleteCurrentHaspInfo(hasp)}
modifyEvent={(hasps) => this.modifyCurrentHaspInfo(hasps)}
key={i}
hasps={hasp}
/>
)}
Use a unique value from the object.
Why you should not use index as a key.
A key is the only thing React uses to identify DOM elements. What happens if you push an item to the list or remove something in the middle? If the key is same as before React assumes that the DOM element represents the same component as before. But that is no longer true.
Source: https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318

filtered elements using computed: problems with paginate in VueJS

I'm using Laravel and VueJs,
I'm trying the following: I 've created a search bar to find users by their names, last name or email.
I used computed to write my filter but I've realized that my filter only filters over the 10 first elements (because I'm using paginate to show all users stored in my database)
...what can I do to make my filter works over all my users instead each ten that gives me paginate (if it's possible keeping paginate, please)?
This is my script and template (thank you very much):
<script>
import UpdateProfile from './users/UpdateProfile';
import CreateUser from './users/CreateUser';
import User from '../models/user';
export default {
components: {UpdateProfile, CreateUser},
data() {
return {
showUpdateModal: false,
showCreateModal: false,
users: [],
user: new User(),
search:'',
paginator: {
current: 1,
total: 1,
limit: 10,
}
}
},
mounted() {
this.goToPage(1);
},
methods: {
userPermissions(user) {
return this.CONSTANTS.getUserType(user.permissions);
},
addUser(user) {
this.showCreateModal = false;
this.api.post('/users', user).then(() => {
this.goToPage(this.paginator.current);
});
},
editUser(user) {
this.user = JSON.parse(JSON.stringify(user));
this.showUpdateModal = true;
},
updateUser(user) {
this.showUpdateModal = false;
this.api.put('/users/' + user.id, user).then(() => {
this.goToPage(this.paginator.current)
});
},
deleteUser(user) {
this.api.delete('/users/' + user.id).then(() => {
this.goToPage(this.paginator.current)
});
},
navigatePrev(page) {
this.goToPage(page)
},
navigateNext(page) {
this.goToPage(page)
},
goToPage(page) {
this.api.get('/users?page=' + page + '&limit=' + this.paginator.limit).then(response => {
this.users = response.data;
this.paginator = response.paginator;
});
}
},
computed:{
filteredUsers: function () {
return this.users.filter((user) => {
var searchByName = user.name.toLowerCase().match(this.search.toLowerCase());
var searchByLastName = user.lastname.toLowerCase().match(this.search.toLowerCase());
var searchByEmail = user.email.toLowerCase().match(this.search.toLowerCase());
if(searchByName){
return searchByName;
}
if(searchByLastName){
return searchByLastName;
}
if(searchByEmail){
return searchByEmail;
}
});
}
}
}
</script>
<template>
<div class="container">
<div class="button is-primary" #click="showCreateModal=true" v-if="CONSTANTS.hasRootPermissions()">
<span class="icon"><i class="fas fa-plus fa-lg"></i></span>
<span>Add User</span>
</div>
<br><br>
<create-user v-if="CONSTANTS.hasRootPermissions()"
:show="showCreateModal"
v-on:save="addUser"
v-on:close="showCreateModal=false"/>
<!--Search Users-->
<div class="control is-expanded">
<h1>Search users</h1>
<input class="input" type="text" v-model="search" placeholder="Find a user"/>
</div>
<br><br>
<!--Search Users-->
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Last Name</th>
<th>Email</th>
<th>Admin</th>
<th>Permissions</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr v-for="user in filteredUsers">
<td>{{user.name}}</td>
<td>{{user.lastname}}</td>
<td>{{user.email}}</td>
<td>{{user.isAdmin ? 'yes' : 'no'}}</td>
<td>{{userPermissions(user)}}</td>
<td>
<div class="button is-info" #click="editUser(user)">
<span class="icon"><i class="far fa-edit"></i></span>
<span>Edit</span>
</div>
</td>
<td>
<div class="button is-danger" #click="deleteUser(user)">
<span class="icon"><i class="far fa-trash-alt"></i></span>
<span>Delete</span>
</div>
</td>
</tr>
</tbody>
</table>
<paginator :paginator="paginator" v-on:prev="navigatePrev" v-on:next="navigateNext"/>
<update-profile :data="user" :show="showUpdateModal" v-on:save="updateUser" v-on:close="showUpdateModal=false"/>
</div>
</template>
You can get all your users (if that's not too much data) at start and then paginate them on a clientside.
Something like:
mounted() {
this.api.get('/users').then(response => {
this.users = response.data;
this.paginator.total = Math.ceil(this.users.length / this.paginator.limit);
});
},
methods: {
goToPage(page) {
this.paginator.current = page;
}
},
computed:{
filteredUsers: function () {
return this.users.filter((user) => {
var searchByName = user.name.toLowerCase().match(this.search.toLowerCase());
var searchByLastName = user.lastname.toLowerCase().match(this.search.toLowerCase());
var searchByEmail = user.email.toLowerCase().match(this.search.toLowerCase());
if(searchByName){
return searchByName;
}
if(searchByLastName){
return searchByLastName;
}
if(searchByEmail){
return searchByEmail;
}
}).filter((el, index) => {
return ( index >= (this.paginator.current - 1) * this.paginator.limit
&& index < this.paginator.current * this.paginator.limit);
});
}
}
}
Update
Other option would be to perform serching on a serverside and to send a search string with every page request:
methods: {
goToPage(page) {
this.api.get('/users?page=' + page + '&limit=' + this.paginator.limit
+ '&search=' + this.search).then(response => {
this.users = response.data;
this.paginator = response.paginator;
});
},
performSearch() {
this.goToPage(1);
},
},
}
with search block in a template:
<!--Search Users-->
<div class="control is-expanded">
<h1>Search users</h1>
<input class="input" type="text"
v-model="search" placeholder="Find a user"
#change="performSearch"/>
</div>
You can add debouncing to get results after you type or add a "search!" button after your search input field to trigger performSearch().
<!--Search Users-->
<div class="control is-expanded">
<h1>Search users</h1>
<input class="input" type="text"
v-model="search" placeholder="Find a user"/>
<button #click="performSearch">Search!</button>
</div>

Resources