How to compare objects of two different arrays in javascript - javascript

I have a react application and in that I have the following list of objects.
const orderItems = [
{
id: 1,
name: "item 1",
price: "100",
availableQty: 2,
out: ""
},
{
id: 2,
name: "item 2",
price: "100",
availableQty: 2,
out: ""
},
{
id: 3,
name: "item 3",
price: "100",
availableQty: 2,
out: ""
},
{
id: 4,
name: "item 4",
price: "100",
availableQty: 2,
out: ""
}
];
Im mapping through the orderItems list and display the name with a checkbox. I have a state named selectedItem and when the checkbox is checked, new object adds to the selectedItem along with the id of the orderItems as shown in the following code.
const handleSelect = (e, item) => {
const { checked } = e.target;
const newObj = {
id: item.id,
isAdded: true,
reason: "",
issue: "",
availableStock: ""
};
if (checked) {
setselectedItem((previousState) => [...previousState, newObj]);
}
if (checked === false) {
const filteredItems = selectedItem.filter(
(singleItem) => singleItem.id !== item.id
);
setselectedItem(filteredItems);
}
};
In the react app, Im mapping the orderItems and showing the name with a checkbox. When the checkbox is checked, I add a new object to selectedItem with the id of orderItems and if the selectedItem is empty, I display a as "list is empty". If checkbox is selected, I display a input tag under the name and if its not selected, i display a label with the text "not selected" as shown in the code below.
<div className="app">
{items.map((item) => (
<div className="issue">
<input type="checkbox" onChange={(e) => handleSelect(e, item)} />
<label>{item.name}</label>
{selectedItem.length > 0 ? (
<>
{selectedItem.map((singleItem) =>
singleItem.id === item.id ? (
<input type="number" />
) : (
<label>not selected</label>
)
)}
</>
) : (
"list is empty"
)}
</div>
))}
</div>
The issue here is, when one item is checked, it show input tag under selected item and shows "not selected" label under other items but if i select two checkboxes, both not selected label and input tag displays. If i select 3 checkboxes, not selected label displays two times with input tag.
What i want is to display only the input tags under selected items and display not selected label under unchecked items.
codesandbox link: https://codesandbox.io/s/minsaf-2jjt2g

You are mapping the selectedItem array for every element in the item array. This means for any element in the array that some condition matches and both the input and label are rendered.
If I understand the code and your expected behavior I think you should conditionally render a single input or label based on if the selectedItem array includes an element matching by id.
Example:
<div className="app">
{items.map((item) => (
<div className="issue">
<input type="checkbox" onChange={(e) => handleSelect(e, item)} />
<label>{item.name}</label>
{selectedItem.length ? (
selectedItem.some((singleItem) => singleItem.id === item.id) ? (
<input type="number" />
) : (
<label>not selected</label>
)
) : (
"list is empty"
)}
</div>
))}
</div>

Related

How to set values for react-select with dynamic rendering of select fields?

I was working on rendering dynamic select fields and trying to set the values for them . Let me explain clearly what i am trying .
At first i have this useState :
const add_actions_options = [
{value : "val1" , label:VAL1},
{value : "val2" , label:VAL2 })}
]
const [ actions , setActions ] = useState<any | undefined>([{type : add_actions_options[0].value , label : "" , data : ""} ])
Initially 1 select field is rendered , but later i have a button which renders more select fields ( Max 4 select fields ) below is the related code for dynamic rendering of Select fields fields:
function addAction(){
if(actions.length < 4 ){
setActions([...actions , {type : add_actions_options[0].value , label : "" , data : ""}])
} else {
toast('max 4 allowed', { type: "error" })
}
}
const handleTypeChange = (index, value) => {
const updatedFields = [...actions];
updatedFields[index].type = value;
setActions(updatedFields);
}
const handleLabelChange = (index , value) => {
const updatedFields = [...actions];
updatedFields[index].label = value;
setActions(updatedFields);
}
const handleDataChange = (index, value) => {
const updatedFields = [...actions];
updatedFields[index].data = value;
setActions(updatedFields);
}
<button className='btn btn-primary btn-sm btn-block' onClick={() => addAction()}>{intl.formatMessage({id: 'ADD.ACTION'})}</button>
<div className='row my-6 '>
{actions.map((item , index) => {
return(
<div key={index} className='row my-6'>
<div className='col-4'>
<h4><label className="form-label">{intl.formatMessage({ id: 'TEMPLATE.TYPE' })}*</label></h4>
<Select
defaultValue={add_actions_options[0]}
onChange={(value) => handleTypeChange(index, value)}
options={add_actions_options}
/>
</div>
<div className='col-4'>
<h4><label className="form-label">{intl.formatMessage({ id: 'TEMPLATE.LABEL' })}*</label></h4>
<input
className="form-control form-control-lg form-control-solid"
name='action.label'
type="text"
maxLength={30}
onChange={(event) => handleLabelChange(index, event.target.value)}
value={actions.label}
required
/>
</div>
<div className='col-4'>
<h4><label className="form-label">{intl.formatMessage({ id: 'TEMPLATE.DATA' })}*</label></h4>
<input
className="form-control form-control-lg form-control-solid"
name='action.data'
type="text"
maxLength={100}
onChange={(event) => handleDataChange(index, event.target.value)}
value={actions.data}
required
/>
</div>
</div>
)
})}
</div>
Here's what i wanted to achieve , the data and label values for actions are working as expected , but the value is being set differently when i choose options from select dropdown,
Initially if i do not change any values for select component it is working as expected , the output :
0: {type:'val1' , label : 'qwe' , data:'ujm'}
1: {type:'val1' , label : 'ujhn' , data: 'uhn'}
Note : In above scenario I am just rendering one more select fields and initially the type is set to add_actions_options[0].value , but if I try to select val2 from the dropdown the output turns to :
0: {type: {value: 'val2', label: 'VAL2'} , label : 'qwe' , data:'ujm'}
1: {type:'val1' , label : 'ujhn' , data: 'uhn'}
//DESIRED OUTPUT WHEN I CHOOSE DIFFERENT OPTION IN SELECT TAG
0: {type: 'val2' , label : 'qwe' , data:'ujm'}
1: {type:'val1' , label : 'ujhn' , data: 'uhn'}
I just want the val2 to be placed within type , but its placing whole selected option , can anyone help me pass this ? Would be great help for me !
Regards

select upto 3 in category list from array in list in react.js

I am working in react, fixed-sized array but I am not getting output when I am select up to 3 record but it show only 1 record select.
CODE:
this.state = {
type: [3], //select upto 3 record(type select from category)
categoryList: null, // category-list
};
changeCategory(o){
this.setState({type: o})
}
<div>
{ categoryList.map((o,index)=>{
return <div key={index} className={"rounded " + (type==o.slug ?"selected" : '')} onClick={()=>this.changeCategory(o.slug)} style={{padding: "2px 5px"}}>{o.name}</div>
})
}
</div>
ISSUE
type is a state array and you are comparing it like the value in the render method. In this way, you always have just one item selected instead of 3 items.
SOLUTION
This code will help you to select 3 items
this.state = {
type: [],
....
};
// this will add selected item in `type` array if length not exceed
changeCategory(o){
if(type.length !== 3){ // for limit of 3
const newType = [...this.state.type];
newType.push(o.slug);
this.setState({type: newType});
}
}
<div>
{categoryList.map((o, index) => {
return (
<div
key={index}
className={
"rounded " + (this.state.type.includes(o.slug) ? "selected" : "")
}
onClick={() => this.changeCategory(o.slug)}
style={{ padding: "2px 5px" }}
>
{o.name}
</div>
);
})}
</div>

Display input fields based on a variable number in state

I have the below piece of code. I have defined a const in state called items. This is the dropdown selection. It has value 0, 1 and 2 and these indicate no. of dependents.
Once user selects this dropdown, i then update the value of selected dropdown in dependents constant using useState.
I want to display input field below this which will allow user to enter dependents age. For e.g. user selects 2 in dropdown. I want to show 2 input fields below which will allow user to enter the age of 2 dependents. Similarly, if i select 1- i should only show 1 input field. In that way it should show dynamically the number of input fields as user selects in dropdown.
Can someone please let me know how to achieve it.
function App() {
const [items] = useState([
{ label: "0", value: "0" },
{ label: "1", value: "1" },
{ label: "2", value: "2" }
]);
const [dependents, setDependents] = useState("0");
return (
<div className="App">
Select Dependents:
<select onChange={e => setDependents(e.currentTarget.value)}>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))
}
</select>
</div>
);
}
"
Create an array based on the selected value and map it to render the input:
<div className="App">
Select Dependents:
<select onChange={e => setDependents(e.currentTarget.value)}>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))
}
</select>
{[...Array(+dependents)].map((_,index)=>{
return <input type="text" key={index} />
})
}
</div>
Note :
[...Array(number)] creates an array of undefined items with length equals to number, and +number converts a string to number like +"4" gives 4

how to select All checkbox based group in reactjs

I did initial state for select single checkbox .Here is my intial state
this.state = {
fruites: [
{ id: 1 , value: "banana", isChecked: false },
{ id: 2, value: "apple", isChecked: false },
{ id: 3,value: "mango", isChecked: false },
{ id: 4, value: "grap", isChecked: false }
]
};
}
Method: I just this for selected all checkbox
handleAllChecked = id => event => {
let fruites = this.state.fruites;
fruites.forEach(fruite => {
data.filter(item =>
fruite.isChecked = event.target.checked;
});
});
this.setState({ fruites: fruites });
};
I just this method for individual checkbox .
handleCheckChieldElement = event => {
let fruites = this.state.fruites;
fruites.forEach(fruite => {
if (fruite.value === event.target.value)
fruite.isChecked = event.target.checked;
});
this.setState({ fruites: fruites });
};
Render:Here is my UI, I want to select All checkbox based on group . For example , I have got two group of value - such as Group , Topgroup. The problem is that , When I click on the group , it will select All checkbox including Topgroup and also I click banana , it will select all banana , I don't want to get all banana when click on one item. I don't to want to get topgroup checkbox when I select on the group.
{[{ id: 1, name: "group" }, { id: 2, name: "topGropup" }].map(item => (
<div>
<input
type="checkbox"
onChange={this.handleAllChecked(item.id)}
value="checkedall"
/>{" "}
{item.name}
<ul>
{this.state.fruites.map((fruite, index) => {
return (
<CheckBox
key={index}
handleCheckChieldElement={this.handleCheckChieldElement}
{...fruite}
/>
);
})}
</ul>
</div>
))}
</div>
How can I resolve this problem . Here is my codesanbox : https://codesandbox.io/s/react-multi-select-checkbox-or6ko
Here, I edited your codesandbox: https://codesandbox.io/s/react-multi-select-checkbox-bbuky
Basically you have 8 checkboxes, even though its 4 items displayed, duplicated for each group.
I added the 4 missing items in your state, but you'd actually want some kind of factory function that lets you create your state given the groups you have.
I had to edit some of your values since you were relying on stuff that now is not unique anymore, like value and use the group's id for example to create a unique identifier groupId-itemId.
Memory pointer to the same list
The groups in the app have the same pointer to memory list of fruits.
because of that the updates will affect on both groups.
See how I fixed it:
https://codesandbox.io/s/react-multi-select-checkbox-r29d1
I found some things in the app that can be improve so I improve them for example:
label to input checkbox to be able to click also on the text
I am here if you have any problem, I suggest you to learn Hooks.

React Semantic UI - add key to options in Dropdown menu

I have this Dropdown menu instance:
<Dropdown
selection
options={this.state.options}
search
value={value}
onChange={this.handleChange}
onSearchChange={this.handleSearchChange}
/>
and when my backend returns response, which is then set as state and it is structured like this:
"options": [
{
"text": "New York,All Airports (NYC) , USA",
"value": "NYC"
},
{
"text": "New York,Newark Liberty Intl (EWR), USA",
"value": "EWR"
},
{
"text": "New York,John F Kennedy (JFK), USA",
"value": "JFK"
},
{
"text": "New York,La Guardia (LGA), USA",
"value": "LGA"
}
]
...I get this warning:
Warning: flattenChildren(...): Encountered two children with the same
key, 1:$BLZ. Child keys must be unique; when two children share a
key, only the first child will be used.
in select (created by Dropdown)
in div (created by Dropdown)
in Dropdown (created by SearchForm)
How do I add keys to these elements to prevent this warning?
So looking at the code for the Semantic UI source for the dropdown component, the render options function converts your passed in options into a array of DropdownItem components:
renderOptions = () => {
const { multiple, search, noResultsMessage } = this.props
const { selectedIndex, value } = this.state
const options = this.getMenuOptions()
if (noResultsMessage !== null && search && _.isEmpty(options)) {
return <div className='message'>{noResultsMessage}</div>
}
const isActive = multiple
? optValue => _.includes(value, optValue)
: optValue => optValue === value
return _.map(options, (opt, i) => (
<DropdownItem
key={`${opt.value}-${i}`}
active={isActive(opt.value)}
onClick={this.handleItemClick}
selected={selectedIndex === i}
{...opt}
// Needed for handling click events on disabled items
style={{ ...opt.style, pointerEvents: 'all' }}
/>
))
}
the key for this array is set by taking the value prop and appending the index to it:
key={`${opt.value}-${i}`}
which should always be unique since the index is used but there is another part of the code for hidden inputs
renderHiddenInput = () => {
debug('renderHiddenInput()')
const { value } = this.state
const { multiple, name, options, selection } = this.props
debug(`name: ${name}`)
debug(`selection: ${selection}`)
debug(`value: ${value}`)
if (!selection) return null
// a dropdown without an active item will have an empty string value
return (
<select type='hidden' aria-hidden='true' name={name} value={value} multiple={multiple}>
<option value='' />
{_.map(options, option => (
<option key={option.value} value={option.value}>{option.text}</option>
))}
</select>
)
}
in this one the key is set to only the value, not the value plus index.
<option key={option.value} value={option.value}>{option.text}</option>
this might be your problem, if you have duplicate values then the key will not be unique. Double check the options list to make sure you don't have duplicate values.

Categories

Resources