React update checkbox from object value - html

I'm trying to control a checkbox by using the value property that is coming from tableData. And by default the value is true.
let newData = newRes.data.map((e) => {
return {
...e,
installmentChecked: true,
lateFeeChecked: true,
depositChecked: true,
collectionChecked: true,
};
});
setTableData(newData);
After I mapped the data, I return the input like this.
const { data, index } = props;
return(
...
<input
type="checkbox"
value={latefee}
checked={data?.lateFeeChecked}
onChange={() => onChangeCheckbox('lateFeeChecked', index,data?.lateFeeChecked)}
/>
...
And this how I handle the value of the object.
const onChangeCheckbox = (key, index,status) => {
tableData[index][key] = !tableData[index][key];
console.log(tableData[index][key], 'props key');
console.log(status, 'status');
};
The problem that I'm getting is, the checkbox won't change at all. When I click, the console says.
false 'props key'
true 'status'
Is there any problem with my code? Or maybe anyone could gimme a better way to handle a checkbox in React?
Appreciate any kind of responses, thanks before.

you need to let react know to rerender your component.
You need to use useState hook to achieve that.
It looks like you have setTableData it is not clear if that's connected to useState by the code you shared.
If it is,
you need to do this:
const onChangeCheckbox = (key, index,status) => {
setTableData({
...tableData,
[index][key]: !tableData[index][key],
});
};

const { data, index } = props;
return(
...
<input
type="checkbox"
value={latefee ? ‘true’:’’}
checked={data?.lateFeeChecked ? ‘checked’ : ‘’}
onChange={() => onChangeCheckbox('lateFeeChecked', index,data?.lateFeeChecked)}
/>
You may try this, as sometimes html doesn’t understand boolean value provided in React, and in those cases we need to provide boolean value in string.

Related

Apparently no causes for the error "TypeError: Cannot read properties of undefined "

I have to show in the layout some data I take from a database. Here is the code I use to fetch the data:
const [array, setArray] = useState([])
const collectionRef = collection(db, "Collection")
const q = query(collectionRef, orderBy("Order", "desc"))
useEffect(() => {
auth.onAuthStateChanged(function (user) {
if (user) {
onSnapshot(q, (data) =>
setArray(data.docs.map((doc) => ({ ...doc.data(), id: doc.id })))
);
}
})
}, [auth]);
Below is the html
<div>
<h2>{array[0].Name}</h2>
</div>
What baffles me most is that the error does not always show up, sometimes everything works and sometimes it stops working without apparent causes. If I do console.log of the array sometimes it prints the data and everything works, sometimes it prints an empty array and does nothing.
I state that that array is never modified, it is loaded at the beginning of the code and the data is only read.
array is empty for the first render and for all the other renders until the data is returned. Try something like:
<div>
<h2>{array.length && array[0].Name}</h2>
</div>

How to initialize checkbox based on dynamic value in React

I am trying to initialize a checkbox to either checked or unchecked based on a value in local storage (chrome extension). I was trying to trigger a function on load that checks the a value in local storage and returns a Boolean value. Since there are multiple checkboxes I need to pass the element id to the function as well.
Here is a semi-pseudo code version of what I was thinking :
const getChecked = (el: any): boolean => {
val = el.id from local storage;
return val;
}
const App = () => (
<div className="App">
<input
type="checkbox"
id="checkboxID"
defaultChecked={getChecked}
/>
</div>
);
But something like this doesn't work because defaultChecked={getChecked} gives me the error " Type '(el: any) => boolean' is not assignable to type 'boolean | undefined'."
Any ideas on what to do?
Thanks.
Please try using checked parameter, instead of defaultChecked.
To get the value from local storage I would suggest you to use a function like this:
const getChecked = (el:any) => {
return JSON.parse(localStorage.getItem("el.id"))
};
Make sure that el.id value is true or false in local storage.

Displaying Node MySQL Results in React Using State

My node.js MySQL query returns a single row wrapped in [RowPacketData] which I can normally access the ID field using results[0].ID.
However, when I store the result in React state (using hooks) it does not work. I can access the result object, but not fields within it.
function MyReactComponent() {
const [dbEntry, setDbEntry] = useState();
useEffect(() => {
const fetchData = async () => {
const result = await queryFunc(`SELECT * FROM table LIMIT 1`);
console.log(result[0]); // <-- Works (shows [RowDataPacket] object)
console.log(result[0].ID); // <-- Works (shows ID)
setDbEntry(result);
};
fetchData();
}, []);
console.log(dbEntry[0]); // <-- Works (shows [RowDataPacket] object)
console.log(dbEntry[0].ID); // <-- TypeError: Cannot read property '0' of undefined
return (
<p>
{dbEntry[0].ID} // <-- How do I render here?
</p>
)
}
What's going on here? I have a feeling React is coercing the result object somehow, but I can't figure it out...
When you need to display data that comes from an async font(API calls for example), it's possible (actually almost certain) that it won't be available by the time the first render occurs, to solve that there is actually a few things you could do:
Placeholder state
You could have a model of what the data will look like described as your initial state, so properties won't be undefined anymore:
const [state, setState] = useState({
data:[
{name: ''}
]
})
Assuming that your data will have this format accessing state.data[0].name won't throw an error. This could be useful in some cases but I personally don't like the approach.
Conditional Render
At each render you should check for a condition and only if satisfied render the piece of code:
return(
<>
<div>Title</div>
{Boolean(state.data.length) && <div>{state.data[0].name}</div>}
</>
)
Suspense
That one is brand new, if you have a component tha't need to perform side effects before render it's content, you should have a fallback content to be displayed while the async action is being perform.
<Suspense fallback={<span>Loading</span>}>
<MYAsyncComponent />
</Suspense>

Unable to add new key-value pair dynamically to a STATE JSON Array in React App

I am trying to add a new key-value pair to the already loaded JSON Array. I am adding the new key-value pair to customize the header column cells in react bootstrap table but getting the below errors. Can any one please help?
'Columns' in the below state is where I wanted to add new key-value pair
state = {
data: MYResult.Products || [],
actualData: MYResult.Products || [],
columns: MYResult.ParametricList_Attributes || [],
isCompareClicked: false,
isDisabled: true,
selected: []
};
This is how I am adding the key-value pair -
componentDidMount(){
checkbox = (column, colIndex) => {
return (
<h5>{ column.text }<checkbox/></h5>
);
}
console.log(this.state.columns) ;
newColumn = this.state.columns.map((column) => {
return {...column, headerFormatter: checkbox};
});
this.setState({columns: newColumn });
}
Full code here - https://codesandbox.io/s/o1r988qkz Please uncomment the componentDidMount() to see the issue
Firstly, there's a typo in dcolumn and column.
And regarding the not defined error, you need to define it using const. Use like:
const checkbox = (column, colIndex) => {
return (
<h5>{column.text}<checkbox /></h5>
);
}
JavaScript variables need to be declared when they are used. Public class syntax can not be used everywhere. The error you're getting is self-evident - 'checkbox is not defined'.
Refer this on how to use it: https://tylermcginnis.com/javascript-private-and-public-class-fields/
I simply declared the undeclared variables in your example and the code worked.

RxJs Interval with takeUntil to publish last value

I have some code which polls until a task is complete
See below
this.simulationStatus =
interval(2000).pipe(
switchMap(
() => from(this.simulationService.getSimulationStatus(this.route.snapshot.paramMap.get('jobId')))),
takeUntil(this.stopPoll),
tap(simulation => {
if (simulation && simulation.complete) {
if (this.stopCount == 1) {
// Get once after complete
this.stopPoll.next(true);
}
this.stopCount++;
}
})
);
I have tried using takeUntil and takeWhile the problem is that that the last value is never published once the task is complete.
To get around this I have to include the tap method to with the stopPoll subject and incrementing the stopCount to get the last value.
So the above works but just feels a bit messy, I'm sure there must be a better way of achieving this?
I would have expected takeUntil to publish the last value or have an override to tell it to e.g takeUntil(observable, {publishLast: true})
BTW Update, the observable is subscribed to by an Angular 6 template
Thanks in advance
One thing you can do is use a custom takeWhile-like operator like this:
const completeWith = <T>(predicate: (arg: T) => boolean) => (
source: Observable<T>,
) =>
new Observable<T>(observer =>
source.subscribe(
value => {
observer.next(value);
if (predicate(value)) {
observer.complete();
}
},
error => observer.error(error),
() => observer.complete(),
),
);
It doesn't seem like a good idea to see it as a variation of takeWhite because it's not just taking values while a condition holds, but also emits an extra value.
It might be that a more elegant solution would be make the simulation status observable emit two kinds of values: next notifications and completion notifications, similarly to how materialize/dematerialize operators work.
This has in the meantime been implemented in rxjs as takeWhile(condition, ?inclusive):
timer(0, 10).pipe(
takeWhile((x) => x < 3, true)
)
emits 0, 1, 2, 3
You can also create subject and emit using next() if you want to complete the observable.
this.stopPoll: Subject<any> = new Subject<any>();
If you want to do complete the subscription. you can call this.stopPoll.next(true);
you can access the data in subscribe()
this.simulationStatus.subscribe(success=>{}, failure=>{}, complete=>{});