how to access a variable outside onClick function react - javascript

I'm trying to get list from the onClick function but I can't if there any solution, please.
here is my full code link
let abe = []
const click = (e) => {
const cityy = e.target.value
const checkUsername = obj => obj.city === cityy;
const result = abe.some(checkUsername)
if (!result) {
abe.push({ "city": cityy})
}
if (!e.target.checked) {
const indexe = abe.findIndex(p => p.city === cityy)
abe.splice(indexe, 1)
}
const simo = watch("simo")
let list = abe.map((list) => list.city).join(" , ")
}

Is the click function triggered in the first place? You have actually missed to show where the click function is used.
Here is an example. Looks like you have to store cities in the state.
const [citiesList, setCitiesList] = useState<string[]>([]);
const click = (e) => {
const cityy = e.target.value
const checkUsername = obj => obj.city === cityy;
const result = citiesList.some(checkUsername)
if (!result) {
setCitiesList(prevState => [...prevState, cityy]);
}
if (!e.target.checked) {
const cList = [...citiesList];
const indexe = cList.findIndex(p => p === cityy)
cList.splice(indexe, 1);
setCitiesList(cList);
}
const simo = watch("simo");
}

Related

Enabling multiple filters for a single array

in my application, there are two types of filters, category and country. However, I am not able to get them to be applied at the same time. For example, I only want the intersection of Category: SaaS + Country: Singapore.
Any advice?
const loadData = props.load
const [card, setCard] = useState(loadData)
const [searchPhrase, setSearchPhrase] = useState("")
const search = (event)=>{
const matchedUsers = loadData.filter((card)=>{
return card.title.toLowerCase().includes(event.target.value.toLowerCase())
})
setCard(matchedUsers)
setSearchPhrase(event.target.value)
}
const filterCountry = (event)=>{
const filteredCards = loadData.filter((card)=>{
return card.country.includes(event.target.value)
})
setCard(filteredCards)
}
const filterCat = (event)=>{
const filteredCards = loadData.filter((card)=>{
return card.cat.includes(event.target.value)
})
setCard(filteredCards)
}
You can change your filter condition to check if the value is in all your considered types
const result = yourData.filter(item => item.country.includes(YOURPHRASE) || item.cat.includes(YOURPHRASE))
you can pass the filtered array as a parameter to the filtering functions :
const search = (event)=>{
const matchedUsers = loadData.filter((card)=>{
return card.title.toLowerCase().includes(event.target.value.toLowerCase())
})
setSearchPhrase(event.target.value);
return matchedUsers
}
const filterCountry = (event,array)=>{
return array.filter((card) => card.country.includes(event.target.value);
}
const filterCat = (event,array)=>{
return array.filter((card) => card.cat.includes(event.target.value);
}
useEffect(() => {
let result = matchedUsers();
result = filterCountry(result);
result = filterCat(result);
setArrayToFilter(result);
}, [searchPhrase]);

How to delete multiple url params

There is a problem with deleting several string parameters. Only the last parameter is being deleted now.
upd: I did not specify that I wanted to achieve the ability to remove specific parameter values
this code does not work correctly:
const updateFiltersSearchParams = (paramKey, newValue) => {
const isParamExist = searchParams.getAll(paramKey).includes(newValue);
if (!isParamExist) {
searchParams.append(paramKey, newValue);
setSearchParams(searchParams);
} else {
const updatedSearchParams = new URLSearchParams(
[...searchParams].filter(
([key, value]) => key !== paramKey || value !== newValue
)
);
setSearchParams(updatedSearchParams);
}
};
const handleDeleteParams = () => {
[...checkboxParams].forEach((param) => {
updateFiltersSearchParams("selected", param);
});
};
Sandbox
change your handleDeleteParams function with this
const handleDeleteParams = () => {
setSearchParams([]);
};
If you want to delete *only the selected (or any specific queryString key) queryString parameters you can use the delete method of the URLSearchParams object, then enqueue the params URL update.
const handleDeleteParams = (key) => {
searchParams.delete(key);
setSearchParams(searchParams);
};
...
<button type="button" onClick={() => handleDeleteParams("selected")}>
Clear all "selected" params
</button>
Solved the problem by modifying the function like this
const toggleSearchParams = (params) => {
const newSearchParams = [...searchParams];
for (const prevParam of params) {
const index = newSearchParams.findIndex(
(newParam) =>
prevParam[0] === newParam[0] && prevParam[1] === newParam[1]
);
if (index === -1) {
newSearchParams.push(prevParam);
} else {
newSearchParams.splice(index, 1);
}
}
setSearchParams(new URLSearchParams(newSearchParams));
};
const handleChangeCheckBoxValue = (e) => {
toggleSearchParams([["selected", e.target.value]]);
};
const handleDeleteParams = () => {
toggleSearchParams(checkboxParams.map((param) => ["selected", param]));
};

Vanilla JavaScript search - how to add multiple fields?

This function is searching from a Json data the field "title".
Please, how can I modify this to include multiple fields, like: "tags", "author" etc.? Thanks!
document.addEventListener('DOMContentLoaded', function(event) {
const search = document.getElementById('search');
const results = document.getElementById('results');
let data = [];
let search_term = '';
fetch('/search.json')
.then(response => response.json())
.then(data_server => {
data = data_server;
});
search.addEventListener('input', event => {
search_term = event.target.value.toLowerCase();
showList();
});
const showList = () => {
results.innerHTML = '';
if (search_term.length <= 0) return;
const match = new RegExp(`${search_term}`, 'gi');
let result = data.filter(name => match.test(name.title));
if (result.length == 0) {
const li = document.createElement('li');
li.innerHTML = `No results found 😢`;
results.appendChild(li);
}
result.forEach(e => {
const li = document.createElement('li');
li.innerHTML = `${e.title}`;
results.appendChild(li);
});
};
});
change
let result = data.filter(name => match.test(name.title));
to
let result = data.filter(name => match.test(name.title) || match.test(name.tags) || match.test(name.auther));
It may be an idea to filter on all entries of the objects within the Array retrieved from the json.
Here's a minimal reproducable example, using Event Delegation.
See also
document.addEventListener(`click`, handle);
const data = getJSONFakeData();
function handle(evt) {
if (evt.target.id === `search`) {
return searchJSON();
}
}
function searchJSON() {
const resultsDiv = document.querySelector(`#results`);
resultsDiv.textContent = ``;
const nothingFound = isEmpty =>
resultsDiv.insertAdjacentHTML(
`beforeend`,
`<h3>${isEmpty
? `😢 No input`
: `No results found 😢`}</h3>` );
const term = document.querySelector(`#term`).value.trim();
if (term.length < 1) {
return nothingFound(true);
}
const re = new RegExp(term, `gi`);
// filter here
const results = data
.filter( entry => Object.entries(entry)
.find( ([, value]) => re.test(value) )
);
if (results.length) {
let elems = [];
results.forEach( result => {
const res = Object.entries(result)
.reduce( (acc, [key, value]) =>
acc.concat(`<i>${key}</i>: ${value};<br>`), ``);
elems.push(`<li>${res}</li>`);
});
return resultsDiv.insertAdjacentHTML(
`beforeend`,
`<ul>${elems.join(``)}</ul>`);
}
return nothingFound();
}
function getJSONFakeData() {
return [{
title: `title1`,
author: `author1`,
tags: `science, medicine`,
editor: `Springer Verlag`
},
{
title: `title2`,
author: `author2`,
tags: `automotive, engine`,
editor: `Elsevier`
},
{
title: `title3`,
author: `author3`,
tags: `programming, functional, loops`,
editor: `Elsevier`
},
];
}
body {
font: normal 12px/15px verdana, arial;
margin: 2em;
}
<input type="text" id="term" value="Elsevier">
<button id="search">Find</button>
<div id="results"></div>

Is there a better way to achieve this?

I am using React. On click of a button, the following function is executed:
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const updatedData = [...prevData];
const updatedItem = updatedData.filter((ele) => ele.id === idValue)[0];
updatedItem.completed = true;
const newData = updatedData.filter((ele) => ele !== updatedItem);
newData.unshift(updatedItem);
return newData;
});
};
My data is an array of objects like this:
[{userId: 1, id: 2, title: "task 1", completed: true}, .....].
Basically I want to move the updated item to the start of the array. Is there any better solution for this?
updatedItem should not be mutated. And this string const newData = updatedData.filter((ele) => ele !== updatedItem); is not fine. You can do it like this :
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const targetItem = prevData.find((ele) => ele.id === idValue);
const updatedItem = { ...targetItem, completed: true };
const filteredData = prevData.filter((ele) => ele.id !== idValue);
return [updatedItem, ...filteredData];
});
};
Even better to reducing an extra filter:
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const targetIndex = prevData.findIndex((ele) => ele.id === idValue);
return [{ ...prevData[targetIndex], completed: true }].concat(prevData.slice(0, targetIndex + 1)) .concat(
prevData.slice(targetIndex + 1)
)
});
};
First find index of updated element using Array.findIndex(), then remove the same element using Array.splice() and add it to front of the array.
const completeTaskHandler = (idValue) => {
setData((prevData) => {
const updatedData = [...prevData];
const index = updatedData.findIndex(obj => obj.id === idValue);
const [updatedItem] = updatedData.splice(index, 1);
updatedItem.completed = true;
updatedData.unshift(updatedItem);
return updatedData;
});
};
The simplest one with only one forEach.
const completeTaskHandler = idValue => {
setData(prevData => {
let updatedItem = {}, newData = [];
prevData.forEach((ele) => {
if (ele.id === idValue) {
updatedItem = ele;
updatedItem.completed = true;
} else {
newData.push(ele);
}
});
newData.unshift(updatedItem);
return newData;
});
};

how to stop Checkbox from getting unchecked when page is refreshed?

So I'm creating a to-do list, and I'm saving the task to the localStorage, when I refresh the page the task stay but the checkbox gets unchecked how could I stop the checkbox from getting unchecked when I refresh the page
note: I'm creating the checkbox via js so when I add a task it creates the checkbox dynamically.
/* arry that holds tasks */
let tasks = [];
/* create a todo object */
const addTask = (text) => {
const todoTask = {
text,
checked: false,
id: Date.now(),
}
tasks.push(todoTask);
renderTodo(todoTask);
};
const formT = document.querySelector(`[data-new-todo-form]`)
const inputT = document.querySelector(`[data-new-todo-input]`)
const todoList = document.getElementById('todo-list');
formT.addEventListener('submit', e => {
e.preventDefault()
let text = inputT.value.trim();
if(text !== '') {
addTask(text);
inputT.value = '';
inputT.focus();
}
})
const renderTodo = (todoTask)=> {
localStorage.setItem('tasksRef', JSON.stringify(tasks));
const item = document.querySelector(`[data-key='${todoTask.id}']`);
if (todoTask.deleted) {
// remove the item from the DOM
item.remove();
return
}
const isChecked = todoTask.checked ? 'done': '';
const node = document.createElement('li')
node.setAttribute('class', `todo-item ${isChecked}`);
node.setAttribute('data-key', todoTask.id);
node.innerHTML = `
<input class="js-tick save-cb-state" id="${todoTask.id}" type="checkbox"/>
<span>${todoTask.text}</span>
<img class="delete" width="15px" height='15px' src="/images/icon-cross.svg" alt="cross">`
;
todoList.append(node);
if (item) {
node.replaceWith(item)
} else {
todoList.append(node)
}
}
todoList.addEventListener('click', e => {
if (e.target.classList.contains('js-tick')) {
const itemKey = e.target.parentElement.dataset.key;
toggleDone(itemKey);
}
if (e.target.classList.contains('delete')) {
const itemKey = e.target.parentElement.dataset.key;
deleteTodo(itemKey);
}
});
const toggleDone = (key) => {
const index = tasks.findIndex(task=> task.id === Number(key));
tasks[index].checked = !tasks[index].checked;
renderTodo(tasks[index]);
}
const deleteTodo = (key) => {
const index = tasks.findIndex(item => item.id === Number(key));
const todoTask = {
deleted: true,
...tasks[index]
};
tasks = tasks.filter(item => item.id !== Number(key));
renderTodo(todoTask);
}
document.addEventListener('DOMContentLoaded', () => {
const ref = localStorage.getItem('tasksRef');
if (ref) {
tasks = JSON.parse(ref);
tasks.forEach(task => {
renderTodo(task);
});
}
});
when you add checkbox to DOM you should set Checked attribute for that.
change renderTodo with this code:
node.innerHTML = `
<input class="js-tick save-cb-state" id="${todoTask.id}" type="checkbox" ${isChecked ? "checked" : ""}/>
<span>${todoTask.text}</span>
<img class="delete" width="15px" height='15px' src="/images/icon-cross.svg" alt="cross">`
;
if you putted your html code I could create live Demo, I think this change will be fixed your problem

Categories

Resources