How to initialize checkbox based on dynamic value in React - html

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.

Related

React update checkbox from object value

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.

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>

Is there a way to fetch data in database from a Ruby-on-Rails models

I have a rails app running alongside with a rails API, there is a constant value for DAYS_LIMIT in config/initializers/constants.rb
DAYS_LIMIT = 40
DEFAULT_PRICE = 1.29
but now in the app i added an input field so that the user decide his DAYS_LIMIT.
So i want to fetch that value from the database from inside the API models.
I have placed breakpoints and can see that inside the API controller, the data is transfered from the app but not to the models.
edited as a question requested , it's a React-on-Rails app , here is the code where the new input field is save to the database (i have removed the other fields so the question look shorter)
export const saveChannel = (files) => {
return async (dispatch, getState) => {
const { channel } = getState();
const {rss_podcast_days} = channel;
const { image } = files;
const save = id ? updateChannel : createChannel;
const sub_required = subscription_required !== undefined ? subscription_required : false;
const formData = new FormData();
formData.append('channel[rss_podcast_days]', rss_podcast_days || '');
if (Object.keys(image).length) {
formData.append('channel[image]', image);
}
const channelId = await dispatch(save(formData, id));
dispatch(fetchChannel(id));
return id;
};
};
from the app controller
podcast_list = RestClient.get("#{ENV['URL_API']}/api/#{#channel.id.as_json}/podcast/list")
#podcasts = JSON.parse(podcast_list.body)
#podcasts = #podcasts.sort.reverse.to_h
this is from the API controller witch the data is transfered from the app
def index
podcasts = #channel.podcasts.published.list(params[:page], params[:items_per_page], params[:ordered_in])
render json: Podcasts::Normalizer.normalize(podcasts, #channel.station.default_podcast_price)
end
and here from the API model that i want to fetch data instead of the constants.
scope :by_days_limit, -> {with_tags.more_recent_than(Date.today - DAYS_LIMIT.days).ordered}
it should take today date minus the value (DAYS_LIMIT) from user input, but for now i get undefined local variable or method if i try to fetch directly
Bro if your class has constant like DAYS_LIMIT you can access it using that class itself for example,
class Demo
DAYS_LIMIT = 5
end
you can access that constant by Demo.DAYS_LIMIT in controller or else wherever you need it.
good luck!
ok , so i finally got it, i don't know if i should delete this thread or just tell how i did it. If it's inapropriate just tell me and i will delete this entire thread.
So here is how i did it, in the API controller i had to add my fetch so that the arguments (list) knows what i am talking about. #channel.days_limit
def index
podcasts = #channel.podcasts.published.list(params[:page], params[:items_per_page], params[:ordered_in], #channel.days_limit)
render json: Podcasts::Normalizer.normalize(podcasts, #channel.station.default_podcast_price)
end
then in the def list of the models, i added days_limit has argument
def list(page = nil, nb_items_per_page = 40, ordered_in = 'desc', days_limit)
ordered_in = ordered_in.in?(['asc', 'desc']) ? ordered_in : 'desc'
page.blank? ? by_days_limit(days_limit) : by_page(page, nb_items_per_page, ordered_in)
end
and finally in the scope of the models, i pass in the new argument
scope :by_days_limit, -> (days_limit) {with_tags.more_recent_than(Date.today - days_limit.days).ordered}
Now the user input from the app is passing to the models via the controller.

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=>{});

Declare a variable and store retrieve data inside

I have managed to retrieve data from Firebase, however, I am unable to store the data into a variable I have declared. I want to store in a variable is so that I am able to use at another method.
Please help.
These are the codes that I have tried.
1st method, rest api
retrieveUser(){
this.restProvider.retrieveUser(this.emailAdd, this.pw)
.subscribe(listUser => {
this.users = userList.results //trying to store to users variable
console.log(listUser);
},
err => {
console.log(err);
},
() => console.log('success')
);}
2nd method to use for some IF-ELSE
loginBtnPress(event){
this.retrieveUser();
console.log(this.users);
}
You are doing it wrong. this.users is getting updated using observables. So, if you try to retrieve its value before the value has been updated, you wont get it as expected. You can call it as below,
retrieveUser(){
this.restProvider.retrieveUser(this.emailAdd, this.pw)
.subscribe(listUser => {
this.users = userList.results //trying to store to users variable
callYourMethodWithUpdatedValue(this.users); // <-- Pass value here
},
err => {
console.log(err);
},
() => console.log('success')
);}
The callYourMethodWithUpdatedValue is called every time(and as soon as) the value this.users is updated
Update 1
You can't retrieve async value in one method and expect that value to be used in some other method on button click. Reason being, your are expecting value on that button click , but since its a async call (can take n secs), you can't be assured that the value will be populated when the value is used through some button call.
That's wrong implementation. You need to change the architecture to either of below:
Don't route to that page unless the user value has been resolved (received). Check canActivate and canActivateChildren.
Change the UX where you are trying to retrieve the use async variable on button click, and activate the button when the value has been received (Here you can use Subject ). Something like this demo