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.
Related
I am having a problem with sessionStorage; in particular, I want the id of the ads to be saved in the session where the user puts the like on that particular favorite article.
However, I note that the array of objects that is returned contains the ids starting with single quotes, as shown below:
['', '1', '7']
but I want '1' to be shown to me directly.
While if I go into the sessionStorage I notice that like is shown as:
,1,7
ie with the leading comma, but I want it to start with the number directly.
How can I fix this?
function likeAnnunci(){
let likeBtn = document.querySelectorAll('.like');
likeBtn.forEach(btn => {
btn.addEventListener('click', function(){
let id = btn.getAttribute('ann-id');
//sessionStorage.setItem('like', [])
let storage = sessionStorage.getItem('like').split(',');
//console.log(storage);
if(storage.includes(id)){
storage = storage.filter(id_a => id_a != id);
} else {
storage.push(id);
}
sessionStorage.setItem('like', storage)
console.log(sessionStorage.getItem('like').split(','));
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
})
})
};
function setLike(id){
if(sessionStorage.getItem('like')){
let storage = sessionStorage.getItem('like').split(',');
if(storage.includes(id.toString())){
return `fas`
} else {
return `far`
}
} else {
sessionStorage.setItem('like', '');
return`far`;
}
}
The main issue you're having is that you're splitting on a , instead of using JSON.parse().
Also, you've got some other code issues and logical errors.
Solution:
function likeAnnunci() {
const likeBtn = document.querySelectorAll('.like');
likeBtn.forEach((btn) => {
btn.addEventListener('click', function () {
let id = btn.getAttribute('ann-id');
//sessionStorage.setItem('like', [])
let storage = JSON.parse(sessionStorage.getItem('like') || '[]');
//console.log(storage);
if (!storage.includes(id)) {
storage.push(id);
}
sessionStorage.setItem('like', JSON.stringify(storage));
console.log(JSON.parse(sessionStorage.getItem('like')));
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
});
});
}
More modular and optimal solution:
const likeBtns = document.querySelectorAll('.like');
// If there is no previous array stored, initialize it as an empty array
const initLikesStore = () => {
if (!sessionStorage.getItem('likes')) sessionStorage.setItem('likes', JSON.stringify([]));
};
// Get the item from sessionStorage and parse it into an array
const grabLikesStore = () => JSON.parse(sessionStorage.getItem('likes'));
// Set a new value for the likesStore, automatically serializing the value into a string
const setLikesStore = (array) => sessionStorage.setItem('likes', JSON.stringify(array));
// Pass in a value.
const addToLikesStore = (value) => {
// Grab the current likes state
const pulled = grabStorage();
// If the value is already there, do nothing
if (pulled.includes(value)) return;
// Otherwise, add the value and set the new array
// of the likesStore
storage.push(value);
setLikesStore(pulled);
};
const likeAnnunci = (e) => {
// Grab the ID from the button clicked
const id = e.target.getAttribute('ann-id');
// Pass the ID to be handled by the logic in the
// function above.
addToLikesStore(id);
console.log(grabLikesStore());
btn.classList.toggle('fas');
btn.classList.toggle('far');
btn.classList.toggle('tx-main');
};
// When the dom content loads, initialize the likesStore and
// add all the button event listeners
window.addEventListener('DOMContentLoaded', () => {
initLikesStore();
likeBtns.forEach((btn) => btn.addEventListener('click', likeAnnunci));
});
I'm making a page for posts that can be viewed by newest or most likes.
I manage this with drop-down lists and arrays.
And whenever the dropdown list is clicked, I have to force update this to match its value.
async selectPosts ({...} = {}, forceUpdate = false) {
let goodOrderByDir = 'desc'
let dateOrderByDir = 'desc'
const db = getFirestore()
let constraints = [ //This array determines the viewing order.
orderBy('date', dateOrderByDir), orderBy('good', goodOrderByDir)]
var hw = document.getElementById('dropDowmListID') //It is linked to a drop-down list.
hw.addEventListener('change', function() {
if (hw.value == 1) { //newest
constraints = [
orderBy('date', dateOrderByDir), orderBy('good', goodOrderByDir)]
}
if (hw.value == 2) { //most likes
constraints = [
orderBy('good', goodOrderByDir), orderBy('date', dateOrderByDir)]
}
})
if (forceUpdate) {
this._lastSelectPostsOptions = {}
}
constraints.push(limit(pageSize))
const queryRef = query(collection(db, 'posts'), ...constraints)
return Promise.all((await getDocs(queryRef)).docs.map(async item => {
this._lastSelectPostsDoc = item
const data = item.data()
return {
...data
}
}))
}
When doing a forced update, the default value is false in the current code.
async selectPosts ({...} = {}, forceUpdate = false)
So when I change the dropdown list I was told it must be true to get the next value.
So I changed the code like this
async selectPosts ({...} = {}, forceUpdate = true)
But I couldn't get the value I wanted...
How can I force an update to apply the changed array values?
I'm working on a project where I need to filter 13 items by two different select box values, and I'm getting stuck on persisting the filter.
I have two select boxes that I've selected like so:
let pickupLocation = document.querySelector("#pa_location"); //values are 'complete-set', 'neck', 'bridge'.
let pickupType = document.querySelector("#pa_type1"); // Values are 'soapbar', 'dogear', 'short'.
What's Working:
I'm initializing an object like so:
const activeFilters = {};
To populate the values like so:
//Persist the Complete Set / Single
pickupLocation.addEventListener("change", function () {
if (pickupLocation.value === "complete-set") {
activeFilters.location = "set";
} else {
activeFilters.location = "single";
}
});
pickupType.addEventListener("change", function () {
if (pickupType.value === "soapbar") {
activeFilters.type = "soapbar";
} else if (pickupType.value === "dogear") {
activeFilters.type = "dogear";
} else {
activeFilters.type = "short";
}
});
// Returns something like
// {location: single, type: dogear}
I'm trying to filter an array of input elements by their value. I have 13 inputs each with a value containing words like set, single, dogear, soapbar etc.
Where I'm stuck:
I have a filter function that I'm trying to filter the values of these inputs by two values of the activeFilters object:
const performFilter = (covers) => {
let results;
let filteredValues = Object.values(activeFilters);
filteredValues.forEach((value) => {
results = covers.filter((cover) => cover.value.indexOf(value) !== -1);
});
return results;
};
The problem is my function is returning only one of the two words. For instance, if the my activeFilters object is {location: set, type: dogear} the filtered results array contains only one of them. Where am I going wrong?
Edit:
This function returns all inputs that match one of the activeFilters, and I apologize if I wasn't clear above, but I'd like it to match ALL of the Active Filters. Is this possible with the function below?
const performFilter = (covers) => {
let results = []; // initialise the array
let filteredValues = Object.values(activeFilters);
filteredValues.forEach((value) => {
let res = covers.filter((cover) => cover.value.indexOf(value) !== -1);
results.push(...res);
});
console.log(results);
};
CODEPEN:
Codepen!
const performFilter = (covers) => {
let results = []; // initialise the array
let filteredValues = Object.values(activeFilters);
filteredValues.forEach((value) => {
let res = covers.filter((cover) => cover.value.indexOf(value) !== -1);
// push the value it find individually
// you were overriding the previous value with result = filter()
results.push(...res);
});
return results;
};
// according to Edited question
const performFilter = (covers) => {
let results = []; // initialise the array
let filteredValues = Object.values(activeFilters);
return covers.filter((cover) => filteredValues.every(value => cover.value.indexOf(value) !== -1));
};
I'm not sure if I understood clearly your question, so feel free to comment it.
First, I suggest you to filter your covers array and inside the filtering function iterate through your selected filters. This is because the filter function returns the array already filtered and so you don't need to assign it to a result variable or things like that. So based on that, try this:
const performFilter = (covers) => {
let results;
let filteredValues = Object.values(activeFilters);
const filteredCovers = covers.filter((cover) => {
return cover.value.split("-").some((tag) => filteredValues.includes(tag))
});
console.log(filteredCovers)
};
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?
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]);