How to reset a select field onChange - javascript

I have a dropdown select component that is populated by what is selected from a set of buttons. Before a selection from the button list is made the dropdown has no choices. But I have created an issue where if a button is selected then another is selected the dropdown still holds the value from the previous selection even tho that item is not suppose to be in the list of options in the drop down. I am trying to figure out a way to reset or clear the selection:
const [location, setLocation] = useState("");
const [thvchecked, setThvChecked] = useState(false);
const [pvchecked, setPvChecked] = useState(false);
const [osvchecked, setOsvChecked] = useState(false);
let emCodeOptions = [];
if (location === "telehealthVisit") {
emCodeOptions = telehealthVisitEMCode;
} else if (location === "telephoneVisit") {
emCodeOptions = telephoneVisitEMCodeChoices;
} else if (location === "onSiteVisit") {
emCodeOptions = onSiteVisitEMCodeChoices;
} else {
emCodeOptions = [];
}
const handleEMCodeChange = (selected) => {
props.onUpdate("emCode", selected.value);
};
const onLocationSelection = (event) => {
let loc = event.target.name;
if (loc === "telehealthVisit") {
setLocation("");
setThvChecked(!thvchecked);
props.onUpdate("visitLocation", loc);
} else if (loc === "telephoneVisit") {
setLocation("");
setPvChecked(!pvchecked);
props.onUpdate("visitLocation", loc);
} else if (loc === "onSiteVisit") {
setLocation("");
setOsvChecked(!osvchecked);
props.onUpdate("visitLocation", loc);
}
setLocation(loc);
};
I though I could do this by resetting the state in the onLocationSlection function but this doesnt seem to work beyond the first time I change my selection.

React doesn't call render method each time u setLocation . It will accumulate the values and smartly call the render with the last value. So setLocation to '' doesn't have the desired effect.
This piece of code looks logically correct to me. Are you updating arrays telehealthVisitEMCode, telephoneVisitEMCodeChoices else where?

Related

Remove item from localStorage after onClick and don't show again anymore after browser refresh in React app

In my React app I am showing a banner yes or no, based on React state and some values set in localStorage.
After close button is clicked, it's state showBanner is saved to localStorage and doesn't show the banner anymore
After 2 times using a page url in the React app with query param redirect=my-site it doesn't show the banner anymore:
import queryString from 'query-string';
const location = useLocation();
const queryParams = queryString.parse(location.search);
const [showBanner, setShowBanner] = useState(true);
const handleClick = () => {
setShowBanner(false);
localStorage.removeItem('redirect');
};
const hasQp = queryString
.stringify(queryParams)
.includes('redirect=my-site');
const initialCount = () => {
if (typeof window !== 'undefined' && hasQp) {
return Number(localStorage.getItem('redirect')) || 0;
}
return null;
};
const [count, setCount] = useState(initialCount);
const show = showBanner && hasQp && count! < 3;
useEffect(() => {
const data = localStorage.getItem('my-banner');
if (data !== null) {
setShowBanner(JSON.parse(data));
}
}, []);
useEffect(() => {
localStorage.setItem('my-banner', JSON.stringify(showBanner));
}, [showBanner]);
useEffect(() => {
let pageView = count;
if (pageView === 0) {
pageView = 1;
} else {
pageView = Number(pageView) + 1;
}
if (hasQp && showBanner === true) {
localStorage.setItem('redirect', String(pageView));
setCount(pageView);
}
}, []);
This is working fine (when you see some good code improvements let me know :) ).
But as soon the user clicks the close button I don't want the localStorage item redirect no longer appears. Now after refreshing the page it appears again.
How do i get this to work?
If this is executing when the page loads:
localStorage.setItem('redirect', String(pageView));
Then that means this is true:
if (hasQp && showBanner === true)
The hasQp value is true, which means this is true:
const hasQp = queryString
.stringify(queryParams)
.includes('redirect=my-site');
And showBanner is true because it's always initialized to true:
const [showBanner, setShowBanner] = useState(true);
It's not 100% clear to me why you need this state value, but you could try initializing it to false by default:
const [showBanner, setShowBanner] = useState(false);
But more to the point, I don't think you need this state value at all. It's basically a duplicate of data that's in localStorage. But since both state and localStorage are always available to you, I don't see a reason to duplicate data between them.
Remove that state value entirely and just use localStorage. An example of checking the value directly might be:
if (hasQp && JSON.parse(localStorage.getItem('my-banner')))
Which of course could be refactored to reduce code. For example, consider a helper function to get the value:
const showBanner = () => {
const data = localStorage.getItem('my-banner') ?? false;
if (data) {
return JSON.parse(data);
}
};
Then the check could be:
if (hasQp && showBanner())
There are likely a variety of ways to refactor the code, but overall the point is to not duplicate data. In thie case a value is being stored in localStorage instead of React state because it needs to persist across page loads. Just keep that value in localStorage and use it from there.

I have a usestate that I want to set I want to set to a value !==null within a function

I am trying to set a state var within a function so when a form button is pressed, the value of the usestate will not equal null anymore. Because the form will not equal null this will perform a different action in my code if this button has been pressed.
Only issue is it seems the variable setReg cannot be set inside of a function as it will not be a global variable. Is there a workaround here?
//the usestate
const [Reg, setReg] = useState(null)
//the function
const updateEthers = () => {
let tempProvider = new ethers.providers.Web3Provider(window.ethereum);
setProvider(tempProvider);
let tempSigner = tempProvider.getSigner();
setSigner(tempSigner);
//Here I am saying if setreg is null as set in the state then perform this
if (setReg == null) {
let tempContract = new ethers.Contract(
phonecontractAddress,
Register_abi,
tempSigner)
setContract(tempContract)
}
//Else use a different function
else {
let
tempContract = new ethers.Contract(
codecontractAddress,
Code_abi,
tempSigner)
setContract(tempContract)
}
}
//I have a button when pressed calls this
const setRegister = async (event) => {
event.preventDefault();
const Hash = await ipfsbcupload(event.target.setText.value);
console.log("sending " + event.target.setText.value + " to the contract");
contract.set(Hash);
setPhoneNum(event.target.setText.value)
let setReg = 1
//let setReg = 1 so that the setReg will no longer be null is the theory so the form will choose the other option when pressed now.
//...
}
setReg() is available globally; however you're missing the function brackets at the end (setReg vs setReg()). That said, what I believe you want to reference is reg.
/* Note that I've made `reg` lowercase to follow camelCase rules */
const [reg, setReg] = useState(null)
const updateEthers = () => {
// this will run fine and is likely the code you want
if (reg == null) { }
// this will return an error - setReg is a function and so needs the parentheses behind it as setReg() - otherwise it will say it's not defined
if (setReg == null) { }
// this doesn't make sense because setReg is just setting what reg should be, it's not a value itself
if (setReg() == null) { }
}

How to checked/uncheck all checkbox in react js?

I want when I checked the child checkbox all the column checkbox should be checked in a row will be check
I want if I checked the parent one all the table checkboxes should be check how i implement I need code example if you have
Note: I am using functional react component with my custom table created by own not any table library.
Thanks every one !
You can do it by this way
Here I am assuming that the data will be in following way:
permissons = [
{create:false, read:false, edit: true, delete:true}
{create:false, read: true, edit: false, delete:true}
]
const checkAll = (event, index) => {
const { checked } = event.target;
const newPermission = [...permissions];
if (checked === true) {
// console.log("Checked");
newPermission[index].create = true;
newPermission[index].read = true;
newPermission[index].edit = true;
newPermission[index].delete = true;
} else if (checked === false) {
// console.log("Unchecked");
newPermission[index].create = false;
newPermission[index].read = false;
newPermission[index].edit = false;
newPermission[index].delete = false;
}
setpermissions([...newPermission]);
};
Pass event and index as props in checkAll function.
You can try the following logic for your first requirement. The logic for second Requirement is similar. You can define some hooks for each row to make it cleaner.
const [row, setRow] = useState({ allChecked: true, permissions: [-1, 1, 1, 1, -1, -1, 1]});
// -1 = does not allow change, 0 = unchecked, 1 = checked
// each index represents a permission, you can use enum to make it clearer
useEffect(() => {
// for update child checkbox
if (row.allChecked && row.permissions.includes(0) {
let updatePermission = ow.permissions.map(permission => permission || 1); // if permission is 0 it will be changed to 1
let updateRow = Object.assign({}, row);
updateRow.permission = updatePermission;
setRow(updateRow);
}
}, [row]}
useEffect(() => {
let updateRow = Object.assign({}, row);
// for update permission checkboxs
if (!row.permissions.includes(0) && !row.allChecked) {
updateRow.allChecked = true;
setRow(updateRow);
} else if (row.permssions.includes(0) && row.allChecked {
updateRow.allChecked = false;
setRow(updateRow);
}
}, [row]);
You need to create a pattern for row and column
For instance
For every row add index of row to each checkbox class like checkbox_${index}
Use queryselectorAll to target them and just trigger click
document.querySelectorAll(`row_${index}`).forEach(el=>el.click())
Similar the case for all checkbox in a column.

Setting state of an array of objects in react js

I am creating a new Array every time an state is changing to display different number of fields on UI.
const [highestEducation, setHighestEducation] = useState([eduObj]);
useEffect(() => {
if (edu === "intermediate") {
const filled = new Array(2).fill(eduObj);
setHighestEducation(filled);
} else if (edu === "graduation") {
const filled = new Array(3).fill(eduObj);
setHighestEducation(filled);
} else if (edu === "postGraduation") {
const filled = new Array(4).fill(eduObj);
setHighestEducation(filled);
} else if (edu === "highSchool") {
const filled = new Array(1).fill(eduObj);
setHighestEducation(filled);
}
}, [edu]);
I am mapping over the highest education to display input on change of input i have declared a function which sets the state accourding to index in highest education array.
const onChangeEdu = (e, id) => {
let value = [...highestEducation];
value[id][e.target.name] = e.target.value;
setHighestEducation(value);
};
but when i change the value of input passing in index and event it updates all object value in highest education array.

Trying to populate array with string values based on filter selections, and filter records by comparing the array to string value of record attribute

I have an API response that returns a list of records each with a 'status' attribute. The status can be 'current', 'former', 'never'.
I have a set of 3 checkboxes that each carry a value for the same that a user would click to filter the list of records accordingly.
The way I'm trying to achieve the filtering functionality is by using a hook for const [statuses, setStatuses] = useState<string[]>([]);
And then populating that array with the value of each checkbox from:
<div>FILTER BY STATUS</div>
<FilterSection>
<span><input type="checkbox" value="Current" onClick={handleStatusChange}/> Current</span>
<span><input type="checkbox" value="Former" onClick={handleStatusChange}/> Former</span>
<span><input type="checkbox" value="Never" onClick={handleStatusChange}/> Never </span>
</FilterSection>
</div>
I then have the onClick method that calls handleStatusChange:
const handleStatusChange = e => {
setStatuses([...statuses, e.target.value]);
props.onFilterChange(statuses, state)
console.log('status value: ', e.target.value)
};
Which passes it's values up to the container component and feeds into the filter function which looks like:
const handleFilterChange = (status: string[], state: string) => {
store.set('currentPage')(0);
const allLocations = store.get('locations');
let filteredLocations = allLocations.slice();
const pageSize = store.get('pageSize');
if (status && status.length > 0) {
filteredLocations = filteredLocations
.filter(l => {
l.financialDetails && l.financialDetails.locationStatus === status;
})
.slice();
}
store.set('filteredLocations')(filteredLocations);
const pagedLocations = filteredLocations.slice(0, pageSize);
store.set('pagedLocations')(pagedLocations);
store.set('locationsLoading')(false);
};
The problem I'm seeing is that I get a TypeScript error inside handleFilterChange saying This condition will always return 'false' since the types 'string' and 'string[]' have no overlap.
EDIT
I've updated the handleStatusChange function and it's populating the array but only on the second click of a checkbox. So on first click it produces an empty array, on second click it grabs whatever the first clicked value was and pushes it into the array so that it's always one click behind what a user actually selected.
I think something like this would work.
const handleStatusChange = e => {
const status = e.target.value;
if (!statuses.includes(status)) {
setStatuses(statuses.concat(status));
}
else {
const statusIndex = statuses.findIndex(status);
statuses.splice(statusIndex, 1);
setStatuses(statuses);
}
props.onFilterChange(statuses)
};
And for the handleFilterChange...
const handleFilterChange = (statuses: string[]) => {
const allLocations = store.get('locations');
let filteredLocations = allLocations.slice();
if (statuses && statuses.length) {
statuses.forEach((status) => {
filteredLocations = filteredLocations
.filter(l => (l.financialDetails && l.financialDetails.locationStatus !== status));
}
const pagedLocations = filteredLocations.slice(0, pageSize);
};
I removed some of the code I thought was irrelevant to the problem.
const handleStatusChange = e => {
const updatedStatus = [...statuses, e.target.value];
props.onFilterChange(updatedStatus, state)
setStatuses(updatedStatus);
console.log('status value: ', e.target.value)
};
you always should call parent (props function) to pass state to parent because when you call setStatuses at that time statuses array is empty so call that
props.onFilterChange
first before setting state.
or in functional component you can use useEffect like this
useEffect(()=>{
props.onFilterChange(statuses, state);
},[statuses]);

Categories

Resources