Puppeteer cannot select attribute tabindex - css-selectors

Subsequent to puppeteer page.select with multiple class doesn't seem to work I now want to select the second dropdown by tabindex but it doesn't work
await page.goto('https://jsitor.com/c0rM-YohL', {
waitUntil: 'networkidle0',
});
const iframeSelector = '.iframe-container iframe';
await page.waitForSelector(iframeSelector, {
visible: true
});
const frameHandle = await page.$(iframeSelector);
const frame = await frameHandle.contentFrame();
await frame.type(".test-element.Input", "test input");
let selected = await frame.select(".test-element.Dropdown [tabindex='2']", "test4");
console.log('selected', selected);

Make sure not to put a space between the class selectors and the attribute selectors:
".test-element.Dropdown [tabindex='2']" ❌
".test-element.Dropdown[tabindex='2']" ✔️
like this:
let selected = await frame.select(".test-element.Dropdown[tabindex='2']", 'test4')
it will result:
selected [ 'test4' ]
Note: you can test CSS selectors yourself in Chrome DevTools Console by typing the selector inside $(). E.g. If you click within the iframe(!) and type $(".test-element.Dropdown [tabindex='2']") it will return null while $(".test-element.Dropdown[tabindex='2']") returns select.test-element.Dropdown.

Related

Extract Select Menu values from modal [discord.js]

I'm currently making a modal based ordering system and extracting the TextInput works fine, however I can't seem to figure out how to extract the SelectMenu data, as the current code only returns an error
TypeError: interaction.fields.getSelectMenuValue is not a function
client.on('interactionCreate', async interaction => {
if (!interaction.isModalSubmit() || !interaction.customId === 'tankform') return;
await interaction.reply({ content: 'Your order was received successfully!', ephemeral: true });
const IGN = interaction.fields.getTextInputValue('minecraft_ign');
const Weapon = interaction.fields.getSelectMenuValue('weapon_type');
const ownedWeapon = interaction.fields.getSelectMenuValue('owned_weapon');
const ownedTanks = interaction.fields.getSelectMenuValue('owned_tanks');
const wantedTanks = interaction.fields.getSelectMenuValue('wanted_tanks');
console.log({IGN, Weapon, ownedWeapon, ownedTanks, wantedTanks})
});
Your code looks fine. The problem is that discord.js doesn't support recieving select menus from modals yet. I suggest you use discord-modals. It works for me personally.
This bit
if (!interaction.isModalSubmit() || !interaction.customId === 'tankform') return;
the 2nd comparison is incorrect, you want
if (!interaction.isModalSubmit() || interaction.customId !== 'tankform') return;
instead
Try:
else if (interaction.type === InteractionType.ModalSubmit) // fixed
{
if(interaction.customId === 'yourId') {
const IGN = interaction.fields.getTextInputValue('minecraft_ign');
const Weapon = interaction.fields.getSelectMenuValue('weapon_type');
const ownedWeapon = interaction.fields.getSelectMenuValue('owned_weapon');
const ownedTanks = interaction.fields.getSelectMenuValue('owned_tanks');
const wantedTanks = interaction.fields.getSelectMenuValue('wanted_tanks');
console.log({IGN, Weapon, ownedWeapon, ownedTanks, wantedTanks})
}

Does anyone have a way to delete id before passing through url? React Axios

Does anyone have a way to delete id before passing through url?
I want to remove the id that is in the addedItems array.
Delete only id. Without interfering with the value inside
onFinish = async(values) => {
const { addedItems, total } = this.state;
values.re_total = total;
const { data, result } = this.props.loginReducer;
await addedItems.forEach((doc) => {
doc.car_number = values.cus_car_number;
doc.reference = values.re_reference;
doc.detail = values.re_detail;
doc.adName = result.data.u_fname;
doc.total = doc.price * doc.quantity;
});
delete addedItems.id;
console.log(addedItems)
await httpClient
.post(`http://localhost:8085/api/v1/revenue/revenue`,{addedItems})
.then((res) => {
console.log(res);
})
.catch((error) => {
console.log("Error :", error);
})
message.success({ content: 'บันทึกรายรับเรียบร้อย!', duration: 2, style: {
marginTop: '5vh',
}} ,100);
await this.props.history.goBack();
};
I'm assuming that the id is in each item of the addedItems array. Rather than it being added to the array directly (addedItems.id = 'bad').
I switched from using a Array#forEach to Array#map so that it creates a new array. Then I use object destructuring with the rest operator (...). So I can pull the id out of the doc object and make a shallow copy of the doc at the same time. The shallow copy is important so we don't accidentally modify state values without meaning to.
That's actually the biggest issue in your code as is - it's modifying the this.state.addedItems unintentionally, as you are changing the docs without doing a shallow copy first.
As for the code: Replace the await addedItems.forEach() with this. You didn't actually need an await there, as Array#forEach doesn't return anything let alone a promise.
const mappedItems = addedItems.map(({id,...doc})=>{
doc.car_number = values.cus_car_number;
doc.reference = values.re_reference;
doc.detail = values.re_detail;
doc.adName = result.data.u_fname;
return doc;
})
Then use {addedItems: mappedItems} as the body of the httpClient.post. So that you use the new array instead of the old one pulled from the state.

How to set slate value based on the plain string value(serialized)

I am building a rich text editor with slate js on React and I need to parse URL from the content(for example: www.website.me should be transformed to www.website.me).
I have already implemented the function to parse URL from plain text and then wrap the content inside the correct tag.
However, the problem is that I need to display the parsed value as soon as the user is typing on the editor(on onChange event). Here is what I have :
onChange = ({ value }) => {
const { isFocused } = value.selection
if (isFocused !== this.state.isFocused) {
this.setState({ isFocused })
}
const string = this.state.html.serialize(value)
const linkifiedString = linkifyHtml(string) || ''
if (value.document !== this.state.value.document) {
const { onChange } = this.props
onChange && onChange(linkifiedString)
}
// this won't work and will call the onChange method infinitely
this.setState({ value: this.state.html.deserialize(linkifiedString) })
}
Thanks for your help.
Finally, I have found the solution, you have to create your own slate plugin or use this one: https://github.com/enzoferey/slate-instant-replace

Multiple Parameters in URL

I have a search form with multiple search filters.
I followed the tutorial example
https://dev.to/gaels/an-alternative-to-handle-global-state-in-react-the-url--3753
It works fine with one search filter, input textbox or checkbox. But now both. The URL looks like this
https://apiurl/?keyword=xxx&checkbox=
OR
https://apiurl/?keyword=&checkbox=item1.
I have no idea how to update both parameter state. Any suggestion? Should I use query parameter object like state={ query:{keyword:'', checkbox:[]}} or just state={keyword:'', checkbox:[]} and how to update URL for multiple parameters?
Thanks.
function getParams(location) {
const searchParams = new URLSearchParams(location.search);
return {
keyword: searchParams.get('keyword') || '',
checkbox: searchParams.get('checkbox') || '',
};
}
function setParams({keyword = "", checkbox = ""}) {
const searchParams = new URLSearchParams();
searchParams.set("keyword", keyword);
searchParams.set("checkbox", checkbox );
return searchParams.toString();
}
state = { keywordValue: "", checkboxValue: "" };
updateKeywordValue = e => this.setState({ keywordValue: e.target.value });
updateCheckboxValue = e => this.setState({ updateCheckboxValue : e.target.value });
use these functions instead of updateInputValue and then create another function, which is triggered on click of a button, that calls the setParams function.
Now calling this.props.history.push(?`${url}\`); will push the values to both the query params
to get the params, you have to do const {keyword, checkbox} = getParams(location);

Get ID from 1st withTracker query and pass to a 2nd withTracker query? (Meteor / React)

Im using React with Meteor. Im passing data to my Event React component with withTracker, which gets and ID from the URL:
export default withTracker(props => {
let eventsSub = Meteor.subscribe('events');
return {
event: Events.find({ _id: props.match.params.event }).fetch(),
};
})(Event);
This is working but I now need to get data from another collection called Groups. The hard bit is that I need to get an ID from the event that I'm already returning.
The code below works when I hardcode 1. However 1 is actually dynamic and needs to come from a field return from the event query.
export default withTracker(props => {
let eventsSub = Meteor.subscribe('events');
let groupsSub = Meteor.subscribe('groups');
return {
event: Events.find({ _id: props.match.params.event }).fetch(),
group: Groups.find({ id: 1 }).fetch(),
};
})(Event);
#Yasser's answer looks like it should work although it will error when event is undefined (for example when the event subscription is still loading).
When you know you're looking for a single document you can use .findone() instead of .find().fetch(). Also when you're searching by _id you can just use that directly as the first parameter. You should also provide withTracker() with the loading state of any subscriptions:
export default withTracker(props => {
const eventsSub = Meteor.subscribe('events');
const groupsSub = Meteor.subscribe('groups');
const loading = !(eventsSub.ready() && groupsSub.ready());
const event = Events.findOne(props.match.params.event);
const group = event ? Groups.findOne(event.id) : undefined;
return {
loading,
event,
group,
};
})(Event);
There's another issue from a performance pov. Your two subscriptions don't have any parameters; they may be returning more documents than you really need causing those subscriptions to load slower. I would pass the event parameter to a publication that would then return an array that includes both the event and the group.
export default withTracker(props => {
const oneEventSub = Meteor.subscribe('oneEventAndMatchingGroup',props.match.params.event);
const loading = !oneEventSub.ready();
const event = Events.findOne(props.match.params.event);
const group = event ? Groups.findOne(event.id) : undefined;
return {
loading,
event,
group,
};
})(Event);
The oneEventAndMatchingGroup publication on the server:
Meteor.publish(`oneEventAndMatchingGroup`,function(id){
check(id,String);
const e = Events.findOne(id);
return [ Events.find(id), Groups.find(e.id) ];
});
Note that a publication has to return a cursor or array of cursors hence the use of .find() here.
It's not very clear which field of the event object should be supplied to Groups.find. But I'll try answering the question.
Try using something like this -
export default withTracker(props => {
let eventsSub = Meteor.subscribe('events');
let groupsSub = Meteor.subscribe('groups');
event = Events.find({ _id: props.match.params.event }).fetch();
return {
event,
group: Groups.find({ id: event['id'] }).fetch(),
};
})(Event);
Note this line -
group: Groups.find({ id: event['id'] }).fetch(),
can be modified to use whichever field you need.
group: Groups.find({ id: event['whichever field'] }).fetch(),

Resources