this.state.pageData.map((elem) =>
elem.map((ele) => {
this.props.AllSelectedFlag ? (
<Td>
{' '}
<Input type="checkbox" value={ele.id} checked={true} onClick={(e) => this.selectHandle(e, ele)} />
</Td>
) : (
<Td>
<Input type="checkbox" value={ele.id} onClick={(e) => this.selectHandle(e, ele)} />
</Td>
);
}),
);
Basically I have to check all the checkboxes when select all button is pressed, I am changing the state of AllSelectedFlag when button is pressed, but the problem is onClick button is not working when the condition is true.
Any other way to solve this?
Approach 1: If you have "checked" property
You don't need to render and apply check properties for checkboxes, you just need to set "checked" property for all elements on "all" selection and reset.
And you can add event onChange on each checkboxes that will be used for individual check/uncheck part.
Refer to example: https://codesandbox.io/s/vvxpny4xq3
Approach 2: if you dont have "checked" property in json
Maintain local array with "ids" inside and oncheck/uncheck add/remove from it and use it for handling check related cases
const [isCheckAll, setIsCheckAll] = useState(false);
const [isCheck, setIsCheck] = useState([]);
const [list, setList] = useState([]);
const handleSelectAll = e => {
setIsCheckAll(!isCheckAll);
setIsCheck(list.map(li => li.id));
if (isCheckAll) {
setIsCheck([]);
}
};
const handleClick = e => {
const { id, checked } = e.target;
setIsCheck([...isCheck, id]);
if (!checked) {
setIsCheck(isCheck.filter(item => item !== id));
}
};
Refer to example: https://codesandbox.io/s/react-select-all-checkbox-jbub2
Related
I am following a tutorial exercise and I got the following error
Objects are not valid as a React child
I know this error is related to the object as I am trying to access the object but it needs an individual item of an object but not sure.
Why cannot the map loop over each item in the array?
Following is my code
var template = <h1>Indecision App</h1>;
var app = {
title: 'Indecision App',
subtitle: 'yo',
options: []
}
let count = 0;
function checkSubtitles (subtitle){
if(subtitle){
return <p>{subtitle}</p>
}else{
return undefined
}
}
function reset(){
count = 0;
reRenderApp();
}
function increaseCount(){
count++;
reRenderApp();
}
function onSubmitHandle(e){
e.preventDefault();
const options = e.target.elements.options;
app.options.push(options);
reRenderApp();
e.target.elements.options.value = ''
}
function removeAll(){
app.options = [];
reRenderApp();
}
function reRenderApp(){
var templateTwo = (
<div>
<h1>{app.title}</h1>
{checkSubtitles(app.subtitle)}
<p>Count: {count}</p>
<p>Array Length: {app.options.length > 0 ? app.options.length : '0 Items'}</p>
<ol>
{app.options.map((item)=>{
return <li key={item}>{item}</li>
})}
</ol>
<hr></hr>
<form onSubmit={onSubmitHandle}>
<input type="text" name="options" />
<input type="submit" value="Push to the Array" />
<input type="reset" value="Empty my list" onClick={removeAll} />
</form>
<button onClick={()=>{
increaseCount();
}}>Increase Count</button>
<button onClick={()=>{
reset();
}}>Reset Count</button>
</div>
)
ReactDOM.render(templateTwo, appRoot)
}
var appRoot = document.getElementById('app');
reRenderApp();
<body>
<div id="app"></div>
<script src="https://unpkg.com/react#16.0.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.0.0/umd/react-dom.development.js"></script>
<script src="./app.js"></script>
</body>
</html>
The main problem is, as you mentioned: Objects are not valid as a React child
But, what is happening?
If we go into:
function onSubmitHandle(e){
e.preventDefault();
// Line 1
const options = e.target.elements.options;
app.options.push(options);
reRenderApp();
// Line 2
e.target.elements.options.value = ''
}
So in Line 1, you're pushing options into the options array.
But, then in Line 2, we can notice options has an attribute (so, it's an object)
So, if you change Line 1, from:
const options = e.target.elements.options;
To this:
const options = e.target.elements.options.value;
It'd work.
Also, to check what I'm saying you have 2 options:
option 1: console.log
function onSubmitHandle(e){
e.preventDefault();
const options = e.target.elements.options;
console.log({ options })
app.options.push(options);
reRenderApp();
e.target.elements.options.value = ''
}
option 2: make that option a valid child of react with JSON.stringify()
<ol>
{app.options.map((item, index)=>{
return <li key={index}>{JSON.stringify(item)}</li>
})}
</ol>
You can do
{app.options.length && app.options.map((item)=>{
return <li key={item}>{item}</li>
})}
But you must be sure that "item" here is not an object as you can't render an object
The reason for this is that your options array is going to be filled with elements as you're pushing the input element with the name of "option" into your array - this elements are objects in JS which you can't render out as list items.
Use React State to store anything that's going to change in the UI - in this case your list of options> So rather than doing
var app = {
title: 'Indecision App',
subtitle: 'yo',
options: []
}
let count = 0;
Do:
const [options, setOptions] = React.useState([]);
const [count, setCount] = React.useState(0);
Title and subtitle are probably not going to change, so just put them in h1 & h2 elements - if they are, then use the state pattern again.
Get rid of the two inputs with types of "submit" & "reset" just use normal button elements instead.
You'll also need an onchange event on your input where the text will go in and each time the onchange event is fired (i.e, when a user types) you'll need to save the input text
const [inputText, setInputText] = React.useState('');
const handleChange = (e) => {
const {value} = e.target;
setInputText(value)
}
<input type="text" value={inputText} onChange={handleChange}/>
Then in your onHandleSubmit function, just have
const onHandleSubmit = () => {
setOptions([...options, inputText]);
setInputText('')
}
This should work
could you help me?, I'm developing with react native and typescript, I need to do this:
I have a checkBox that tells the user to check if his name is the same as his credit card, if he clicks the checkbox, a TextInput with his name is autocompleted,
if you don't click the checkbox that he can type his name.
I have a variable like: user_name
I don't have code because I don't know how to do it, but I think it goes something like this:
const [checked, setChecked] = useState(false)
...
return(
<CheckBox
checked={setChecked}
onPress={}
checkedIcon='dot-circle-o'
uncheckedIcon='circle-o'
checkedColor='blue'
uncheckedColor='blue'
/>
<TextInput
placeholder='Nombre completo'
value={}
onChangeText={}
)
We could implement this as follows under the assumption that the name of the credit card is available. Let us call it creditCardName.
My example uses react-native-checkbox and the standard TextInput component. If you are using a different component, then the overall pattern still stays the same.
const [isChecked, setChecked] = useState(false);
const [userName, setUserName] = useState('');
return (
<CheckBox
value={isChecked}
onPress={(newVal) => setChecked(newVal)}
/>
<TextInput
editable={!isChecked}
placeholder='Nombre completo'
value={isChecked ? creditCardName : userName}
onChangeText={setUserName}
/>
)
The key-parts are as follows:
Let the TextInput be editable if and only if isChecked is false, that is the CheckBox is unchecked.
Let value of the TextInput be the creditCardName if the CheckBox is checked and set it to the userName otherwise.
This code should work (run the snippet for demonstration)
const checkbox = document.getElementById('checkBox')
var input = document.createElement('input')
var submit = document.querySelector("#submit")
var name = "Tom"
checkbox.addEventListener('change', (event) => {
if (event.currentTarget.checked) {
document.querySelector("body").appendChild(input)
input.value = name
} else {
input.parentNode.removeChild(input)
input.value = ""
}
})
submit.onclick = function() {
console.log(input.value)
}
<input type="checkbox" id="checkBox">
<button id="submit">Submit</button>
I am trying to handle multiple checkboxes as follows:
sendFileNameToBackEnd = (filename: string[]) => {
console.log(filename)
this.vizsualizaForFileName(filename)
}
render() {
const handleChange = (checked: boolean, event: React.FormEvent<HTMLInputElement>) => {
let listoffilename : Array<string> = []
const target = event.currentTarget;
const name = target.name;
if(checked && name !== '')
{
listoffilename.push(name)
this.setState({
listoffilename1: listoffilename
});
}
console.log(this.state.listoffilename1)
};
return (
<DataList aria-label="Checkbox and action data list example" isCompact >
{ this.state.fileListData ?
this.state.fileListData.map((fd) =>
<DataListItem aria-labelledby="check-action-item1">
<DataListItemRow>
<DataListCheck
id="controlled-check"
aria-labelledby="check-action-item"
isChecked={isChecked1}
onChange={handleChange}
name={fd}/>
<DataListItemCells
dataListCells={[
<DataListCell key="primary content">
<span id="check-action-item1">{fd ? fd : "Loading..."}</span>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
):
<>
<EmptyState>
<Title headingLevel="h4" size="lg">Empty state</Title>
</EmptyState>
</>
}
</DataList>
<Button variant="primary" onClick={ () => {this.sendFileNameToBackEnd(this.state.listoffilename1)}}>Visualize</Button>
);
}
In the above code, when I select any checkbox, I can get its value, but when I choose multiple checkboxes I only getting one value in an array.
In 'this.state.fileListData' I have n number of data and I am displaying a checkbox using a map and one button called 'Visualize'. When we select some of the values from the checkbox and click on the 'Visualize' button, I want to send all selected values to the backend for another operation.
When I select multiple checkboxes then it only sends one value in it not all selected values.
Guide me if I am doing something wrong.
I tried to implement something like a multi-select, where the user can either select a value from a data list or can type in a new value. A chosen value should be added to an array if the user presses enter. For detecting changes in the input field I use onChange and a state variable that saves the current value typed in. For detecting the press of enter I use onKeyDown. The problem is that I'm no longer able to type something in the input field, however choosing values from the data list works. I figured out that when I comment out onKeyDown, I can type something in the input field and can also choose from values provided by the data list. However, in this case, adding values to an array on the press of enter doesn't work. I'm fairly new to React, is there something I miss?
My current code looks like follows:
const EditableMultiSelect = ({ field, helpers, metadataField, editMode, setEditMode }) => {
const { t } = useTranslation();
const [inputValue, setInputValue] = useState('');
const handleChange = e => {
const itemValue = e.target.value;
setInputValue(itemValue);
}
const handleKeyDown = event => {
event.preventDefault();
if (event.keyCode === 13) {
field.value[field.value.length] = inputValue;
helpers.setValue(field.value);
setInputValue("");
}
}
const removeItem = () => {
console.log('to be implemented');
}
return (
editMode ? (
<>
<div
onBlur={() => setEditMode(false)}
ref={childRef}>
<input name="inputValue"
value={inputValue}
type="text"
onKeyDown={e => handleKeyDown(e)}
onChange={e => handleChange(e)}
placeholder={t('EDITABLE.MULTI.PLACEHOLDER')}
list="data-list"
/>
<datalist id="data-list">
{metadataField.collection.map((item, key) => (
<option key={key}>{t(item.value)}</option>
))}
</datalist>
</div>
{(field.value instanceof Array && field.value.length !== 0) ? (field.value.map((item, key) => (
<span className="ng-multi-value"
key={key}>
{t(item)}
<a onClick={() => removeItem(key)}>
<i className="fa fa-times" />
</a>
</span>
))) : null}
</>
) : (
<div onClick={() => setEditMode(true)}>
{(field.value instanceof Array && field.value.length !== 0) ? (
<ul>
{field.value.map((item, key) => (
<li key={key}>
<span>{item}</span>
</li>
))}
</ul>
) : (
<span className="editable preserve-newlines">
{""}
</span>
)}
<i className="edit fa fa-pencil-square"/>
</div>
)
);
};
You're calling event.preventDefault() every time a key is pressed. You should move it inside the if statement:
const handleKeyDown = event => {
if (event.keyCode === 13) {
event.preventDefault();
field.value[field.value.length] = inputValue;
helpers.setValue(field.value);
setInputValue("");
}
}
you can't type anything anymore in the input text because in the handleKeyDown event handler, you're calling event.preventDefault() in the early lines. So i think you just have to move it into the if case:
const handleKeyDown = event => {
if (event.keyCode === 13) {
event.preventDefault();
field.value[field.value.length] = inputValue;
helpers.setValue(field.value);
setInputValue("");
}
}
Remove e.preventDefault() or put it inside the if statements.
It is the one preventing the input from being editable.
I want to fill the inputs value of a form with default values once the modal is opened
I did it with pure javascript using document.getElementById(textId).value='some value as follow:
for(var i=0; i<details_data.length;i++){
let textId='text'+i;
let amountId='amount'+i;
document.getElementById(textId).value=details_data[i].text
}
This worked fine. but I want to know how to do it with React since I don't believe this is a best practice.
what i tried is to set the input value like this:
<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
But this woudn't let me change the value of the input. it just set the default value, and when i type in the input the value woudn't change as I want.
This is my code
const [details_data,set_details_data]=useState([
{'text':'','amount':''}
])
// called this function on `onChange` and store the data in `details_data`
function details_handler(e){
let name=e.target.name;
let value=e.target.value;
details_data[this][name]=value;
set_details_data(details_data);
}
JSX:
(In my case user can add inputs as many as he wants,That's why I put the inputs in a the mapping loop)
{
details_data.map((el,index) => {
let textId='text'+index;
let amountId='amount'+index;
return (
<div key={index}>
<input name='text' id={textId} value={el.text} onChange={details_handler.bind(index)}/>
<input name='amount' id={amountId} onChange={details_handler.bind(index)}/>
</div>
);
})
}
useEffect(() => {
if(detailsProps) {
set_details_data(detailsProps);
}
}, [detailsProps])
where your detailsProps (data from the api) will look something like this
detailsProps = [
{'text':'text1','amount':'100'},
{'text':'text2','amount':'200'}
]
onChange Function
const details_handler = (event, index) => {
const items = [...details_data];
items[index][event.target.name] = event.target.value;
set_details_data(items);
}
your view
{
details_data.map((el,index) => {
return (
<div key={index}>
<input name='text' value={el.text} onChange={(e) => details_handler(e, index)}/>
<input name='amount' value={el.amount} onChange={(e) => details_handler(e, index)}/>
</div>
);
})
}