Is there any way to check only the required checkboxes? - checkbox

I am trying to only select limited items which has DOM as below:
<div class="checkbox-wrap">
<div class="wb-checkbox">
<input id="Account" name="Account" type="checkbox" value="true"><input name="Account" type="hidden" value="false">
<label for="Account">Account</label>
<span class="check-mark"></span>
</div>
</div>
For selecting all the items, I used following code:
it('Select all items', ()=>{
cy.get('#WallTransportationModeId').select('Wallbee-Road')
cy.get(':nth-child(n) > .checkbox-wrap > .wb-checkbox > label').click({ multiple: true, force: true })
cy.get('#btn-save-transportation-layout-setup').click()
})
All the items are selected as well. But now I need to only select 10 first items.

You can apply a filter method in between the selection (which grabs multiple elements) and the action
cy.get(<selector-that-selects-multiple-elements>)
.filter((index, element) => index < 10) // first 10 elements only
.click({ multiple: true })
You can use any kind of javascript expression inside the filter function,
.filter((_, element) => element.innerText.startsWith('A')) // labels beginning with "A"
Selecting random elements
const totalCheckboxes = 20;
const numberToSelect = 10;
const randomIndexes = Array.from(
{length: totalCheckboxes}, // empty array
() => Math.floor(Math.random() * totalCheckboxes) // map to random indexes
).slice(0, numberToSelect) // take as many as wanted
cy.get(<selector-that-selects-multiple-elements>)
.filter((index) => randomIndexes.includes(index)) // apply randomness
You can get some repeats with this, which is probably not what you want. Take a look on SO for "non-repeating random numbers" and adjust this code accordingly.

Related

.filter() function creating loop in delete function - React

I've got a 'list' component, which allows you to add an item to a state array, and then display it from the state afterwards. These list items can then be removed by the user afterwards (or should be able to).
There's four state props in this component:
currentList: content in the input that's to be added to the list array
setCurrentList: what's used to change the content in the input
fullList: the full array list
setFullList: used to add the currentList content to the array, and removed
I'm using .filter() to create a copy of the state array, and then set the state afterwards in this function:
const deleteFromList = (e) => {
console.log("Delete button pressed")
console.log(e)
let fullList = props.fullListState
let setFullList = props.setFullListState
let filteredArray = fullList.filter(item => item)
setFullList(filteredArray)
}
However, every time I execute this function (i.e. when the delete button is pressed), it just creates a loop and the first two console.logs are just repeatedly done.
This is the full return function itself:
<>
<label className="setup-jobs-label">{props.label}</label>
<div className="setup-jobs-input-container">
<input className="setup-jobs-alt-input" type="text" onChange={onChange} value={props.currentListState} />
<button className="setup-jobs-add-button" onClick={addToList}>Add</button>
</div>
{ props.fullListState === [] ? null : props.fullListState.map(x => {
return <div className="setup-jobs-input-container" key={props.fullListState[x]}>
<p className="setup-jobs-input-paragraph">{x}</p>
<button className="setup-jobs-delete-button" onClick={deleteFromList(x)}>Delete</button>
</div>
}) }
</>
The important bit is the bottom conditional render, which checks to see if the state array is empty, and if so, not display anything. If it isn't, then it returns null.
Any advice would be appreciated - not sure what I'm doing wrong in the filter function.
In your onClick handler, you pass the result of the execution of deleteFromList, you should pass a reference to this function instead :
// note the '() =>'
<button className="setup-jobs-delete-button" onClick={() => deleteFromList(x)}>Delete</button>
See https://reactjs.org/docs/handling-events.html for more details about this.
Beside this, your filter logic does not seem right :
// this line only removes falsy values, but not the "e" values
let filteredArray = fullList.filter(item => item)
// you should implement something like this
let filteredArray = fullList.filter(item => [item is not "e"])
// this should work as we work on objects references
let filteredArray = fullList.filter(item => item !== e)

How to properly check the current Index of an array in a React map?

I'm trying to increase the value of an array of an specific position. Let's say you have an array:
const [cantidad, setCantidad] = useState([
{cantidadID: 1, value: 1},
{cantidadID: 2, value: 1},
{cantidadID: 3, value: 1}
]);
Now I would like to change the value of ONLY one of those (doesn't matter which one) with a button
const plus = (e) => {
setCantidad(cantidad[e] + 1);
};
const minus = (e) => {
if (cantidad[e] > 0){
setCantidad(cantidad[e] - 1);
} else {
window.alert("Sorry, Zero limit reached");
setCantidad(0);
}
};
e being the index of the array (with some smart coding ofc) being send from a table pretty much like this
{libros.map((l) => (
<tr>
<td>
<button onClick={mas} />
{cantidad}
<button onClick={menos} />
</td>
<td>{l.grado}</td>
<td>
<input
onChange={(event) => {
let checked = event.target.checked;
}}
type="checkbox"
checked=""
>
</input>
{l.descripcion}
</td>
<td>{l.editorial}</td>
<td>${parseFloat(l.precio).toFixed(2) * cantidad}</td>
</tr>
))}
// I know the checkbox is not working. I'm still working through that.
Now in my head it does make sense that while is mapping there should be a variable controlling the Index of the cantidad variable but if I try to make a new variable inside the map it goes crazy and it crashes, (Unless i'm formating it wrong or putting it in the wrong place)
So I got the logic is very simple but I do not know how to apply it it would be something like:
If you have X[] Variable while mapping make a Y variable that controls the ID of the array variable and if you want to change the value of an specific value from X[] then you must send the X[Y] variable to the button const plus and minus and then only change that variable from that specific ID.
In my full code I'm not using 3 values btw the values are equal to the amount of data that is bringing from the map
Any tips, data or information is appreciate it. If you require the actual input with my whole code let me know as well if I do not get it working I'll probably post the code later.
This is the actual code I'm working on and even though the first question got answered I'm still having issues with the next part (Only relevant part)
const [amount, setAmount] = useState([1]);
//I know this bit doesn't make sense (Yet) I'm trying to figure out first the first bit
const plus = (index) => {
setAmount(amount[index] + 1);
};
const menos = (index) => {
if (amount[index] > 0){
setAmount(amount[index] - 1);
}
else {
window.alert("Sorry, Zero limit reached");
setAmount(0);
}
};
{books.map((l, index) => (
<tr >
<td>
<button onClick = {() => plus(index)}/>
{amount[index]}
<button onClick = {() => minus(index)}/>
</td>
<td>{l.grado}</td>
<td >
<input onChange = {(event) => {
let checked = event.target.checked;
}}
type="checkbox" checked = "">
</input>
{l.descripcion}
</td>
<td >{l.editorial}</td>
<td >${parseFloat(l.precio).toFixed(2) * amount[index]}</td>
</tr>
))}
and this is how is printing
I know in Javascript you can use Array(5).fill(2) is there something similar to that? like I would like to do Array(map.length).fill(1) for example so the value always starts with 1 and then all I have to do is to play with the index to change the correct one with plus and minus.
It is the second argument of .map function so:
libros.map((l, idx)
where idx is your i
Here is documentation about it
You are setting an object in an array based on the index value, and not an actual id. Recommend heavily that you incorporate an id into each object, then grab the object by id to manipulate it. Otherwise you could experience bugs and unexpected behaviors as you manipulate the array.
Same concept as not using the index of an array when using map: this is an anti-pattern.
https://reactjs.org/docs/lists-and-keys.html

How to target only the last item in a v-for array?

I have an array of objects inside v-for to create a component for each item like so:
<div v-for="(expense, idx) in myExpenses" :key="idx">
<expense-panel
v-model.number="expense.expensesValue"
:expense="expense"
:myExpenses="myExpenses"
:showEdit="showEdit">
</expense-panel>
</div>
I have a method to add and extra "expense" to the array:
(I logged the item I am trying to specifically target)
addExpense() {
this.myExpenses.push({
expensesKey: "",
expensesValue: null,
subExpense: null,
});
//The last item in the array
console.log(this.myExpenses[this.myExpenses.length - 1]);
},
Is there a way in Vue to specifically add an input element to the last item of the array?
I have a showInput = false in the parent's Data() already.
You could for example add a slot to expense-panel and conditionally render your-input there only if it's the last item that is being rendered, like this:
<div v-for="(expense, idx) in myExpenses" :key="idx">
<expense-panel
v-model.number="expense.expensesValue"
:expense="expense"
:myExpenses="myExpenses"
:showEdit="showEdit">
<your-input v-if="idx === myExpenses.length - 1" />
</expense-panel>
</div>
Other alternative could be passing a prop to the panel (like is-last) and baking the input into the expense-panel.
Also, if the input should be rendered visually AFTER the last item, you can simply add input after the whole list:
<div v-for="(expense, idx) in myExpenses" :key="idx">
<expense-panel
v-model.number="expense.expensesValue"
:expense="expense"
:myExpenses="myExpenses"
:showEdit="showEdit">
</expense-panel>
</div>
<your-input />

In Cypress to test getting total number of elements from listbox and then according to the data run in loop and as per each data perform an if

In Cyress Test writing an test of react application when I click on a Listbox in the drop down it get list of data.
eg : 123a, 1233, 111c etc suppose have count 50
then select each 1 by 1 however need to compare each that if its certain account perform certain checks
in details:
have searched and clicked the listbox but the issue i am facing how can i find the total number of elements in that listbox and need to traverse each item/value 1 by 1 and when select verify certain asserts.
so 3 challenges where i am stuck
1) How to get total number of elements have tried initial count=cy.get('#alias').length seems not working.
2) after we get how can I iterate through the loop 1 at a time as after selecting 1 item as have to certain assertions.
Thanks
Varun Awasthi
First:
cy.get("alias").length can never work because of the async structure of cypress. The get() returns never the wrapped element but a chainable. Thus you would have to write something like get(..).then(obj => ...)
Second:
Given this HTML structure:
<div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
<div class="item">
...many other html code
</div>
</div>
You can get the length ( = the mount of item elements) like this:
it("test", () => {
cy.get(".item").should($items => {
cy.log(`amount: ${$items.length}`)
})
})
Third:
Please try something like this:
it("test", () => {
cy.get(".item").each($item => {
cy.wrap($item).should($e => {
expect($e.text()).to.eq("test")
})
})
})
But you must not use cypress commands here. Something like this should also work:
cy.get(".item").should($items => {
for(var i = 0; i < $items.length; i++) {
expect($items[i].text()).to.eq(...)
}
})
So you can also work with a combination of cypress commands and jQuery.
Let me know if you need furhter assistance
I am new to this, but to get the count of elements returned I would use something like this:
cy.get('.item').its('length')
Then, if you want to work with specific elements from that array:
.then(size => {
for(i= 0; i < size: i++) {
cy.get('.item').eq(size).should('have.value', 'list item')
}
})

Conditional classes on single instances of component within a loop

I have a loop of components that make a grid and I want some instances to have a background color change triggered by adding a class.
This question gave me ideas but I've yet to get them to work.
I have this basic markup in it.
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
And I have an array of the indexes representing the component instances that I want the color changed on
let indexes = [101, 178, 232, 545]
Currently I am doing it with plain JS, via document.querySelector('.box:nth-of-type(101'), but as this method bypasses React I want to change it.
Based on the other question I tried making an array of all the components and setting that to state, then looping through and using the indexes. I don't know how to "access" the component like this and get $$typeof: Symbol(react.element) etc
let compArr = []
this.arr.map((i) => {
compArr.push(
<div className={`box ${(this.state.backgroundColor ? 'backgroundColor' : null)}`} key={i}>
</div>
)
})
this.setState({
compArr: compArr
})
Then later loop over indexes:
indexes.map(index => {
this.state.compArr[index] ===> ??stuck here??
})
Expected Output: So on an array of three instances, say I want the second one only to have the class of backgroundColor:
<div className='box' </div>
<div className='box backgroundColor'</div>
<div className='box'</div>
Only in my case, I want the instances to correlate with the indexes array
How can I set the conditional class to true in those instances I have in the array? Say I have like 500+ instances total.
If I understand you correctly this is proably what you're looking for...
let indexes = [101, 178, 232, 545]
let compArr = this.arr.map((obj, i) => {
return (
<div
className={`box${( indexes.includes(i) ? " backgroundColor" : "")}`}
key={i}
>
</div>
);
})
this.setState({
compArr: compArr
})
If your goal is only to return the given div with the className backgroundColor for every element in this.arr with its index included in the indexes array then...
You only need to iterate over the array once and can perform all the necessary logic you're currently doing performing in two.
You don't need to use Array.push() to an outside collector when using any of the pure functions like map() or reduce() because they return a new version of whatever array is iterated over.
If for whatever reason you want a distinct array of <div>s with an index in indexes then you should use reduce...
let compArr = this.arr.reduce((acc, obj, i) => {
if (!indexes.includes(i)) return acc;
return [
...acc,
<div className="box backgroundColor" key={i}></div>
)]
},[])

Resources