how to update array of objects when input is changed - javascript

I have an array of objects
const data= [
{ id:1,name:"apple", city:"ban" },
{ id:2,name:"mango", city:"hyd" }
]
And I have two input fields when the user fills. if !null then I need to add an object to "data" {id:2,name:"apple",city:"nel"} and the id of the 2 in the data object should be 3 and if again the user makes it to null ie deleted the value from the input field need to remove this {id:2,name:"apple",city:"nel"} and make the id from 3 to 2. similarly of the user gives 2 inputs i need to add 2times {id:2,name:"apple",city:"nel"},{id:3,name:"apple",city:"nel"} and make the id of 2 to 4. similarly if the user deletes eaither/or deletes both or single data from the input i need to add or remove the data array accordingly can anyone please help me with this in react with hooks

You can track the form values with a single useState() hook.
You can use both input onChange event handlers, and form onSubmit event handler to build a component that behaves like you want.
The following is an example React component with hooks you can take as a starting point to manage your state. Please take it as a template and tweak it as needed to fulfill your actual requirement.
const storedData = [
{ id: 1, name: 'apple', city: 'ban' },
{ id: 2, name: 'mango', city: 'hyd' },
]
let nextId = 3
const MyFormComponent = () => {
const initialFormData = { name: '', city: '' }
const [formData, setFormData] = useState(initialFormData)
const clearFormData = () => {
setFormData(initialFormData)
}
const handleOnInputChange = (event) => {
const { value, name } = event.target
// merge previous formData with the new value from input
setFormData({
...formData,
[name]: value,
})
}
const handleOnSubmit = (event) => {
// prevent HTML form default handler (navigation, etc.)
event.preventDefault()
const { name, city } = formData
// OPTIONAL: handle form data validations
if (name === '') {
// no "name" provided
alert('Must specify a name!')
return
}
// input1 "name" and input2 "city" are available in formData
// TODO handle the form data and implement your application logic / update storedData / etc.
// TODO a rough example below, please tweak it to match your requirements
const existingEntryByIndex = storedData.findIndex(
({ name }) => formData.name === name
)
if (existingEntryByIndex >= 0 && formData.city === '') {
// name exists and city value is empty => delete this entry
// NOTE: city value can't be null, because it will be always a string. Maybe, you can use "null" string though.
storedData.splice(existingEntryByIndex, 1)
} else {
// name exists and city not empty, or name is new => add a new city
storedData.push({ id: nextId, name, city })
nextId++
}
// --- end of rough example ---
// OPTIONAL: clear the form values ->
clearFormData()
}
return (
<div className={'my-form-container'}>
<form onSubmit={handleOnSubmit}>
<input
type="text"
name="name"
value={formData.name}
onChange={handleOnInputChange}
/>
<input
type="text"
name="city"
value={formData.city}
onChange={handleOnInputChange}
/>
</form>
</div>
)
For further reference, you can check the React docs to learn about more techniques and ways to handle form inputs, and events.

Related

Filter array of objects if property value includes the string passed to it

I have an array of object as follows
const myArray = [
{
id:31,
name: "test"
},
{
id:22
name: "transit"
},
{
id:25
name: "tomato"
}
];
Now here is the scenario, user starts entering the text, if users enters t as input, i will get all 3 objects in the result because the name property has text t at the start (test, transit, tomato)
Now user enters to at the input, i want only the object with name tomato in the result.
In order to achieve this above scenario, i implemented the following
const propsToCheck = ['name'];
const userInput = 'To';
let result = myArray.filter(o =>
propsToCheck.some(k => userInput.toLowerCase().includes(String(o[k]).toLowerCase())
)
);
It doesnot provide correct result. can someone please let me know if i am doing it right or if there is any easy implementation to achieve the same result.
You're doing it the wrong way - you should be testing if the input is included in the string, not if the string is included in the input:
let result = myArray.filter(o =>
propsToCheck.some(k => String(o[k]).toLowerCase().includes(userInput.toLowerCase()))
);

Filtering Multiple input on a single json

I have a json file with object
obj= [{fname:"abhi",age:5,class:"ten",lanme:"kumar"
},{fname:"abhi",age:5,class:"ten",lanme:"kumar"
},{fname:"abhi",age:5,class:"ten",lanme:"kumar"
},{fname:"abhi",age:5,class:"ten",lanme:"kumar"
}]
which I display in the following table
enter image description here
i am trying to build a filter for the above table but I am not able to filter it out
Can anyone please help me on this
Note: Second Row each Column is a Filter for only that column that is Class searches only class column not everything
And that search should populate in that table
Can anyone please help I am stuck here from ages on this specially with useState Hook
Stack Used : React & Javascript no third party library
Currently my filter is something like this
const [value, setValue] = useState({
lastname: '',
class: '',
firstname: '',
});
const handleSubmit = e => {
const searchValue = {
...value,
[e.target.name]: e.target.value
};
setValue(searchValue);
setCopyList(
copyList.filter(item => item[e.target.name].includes(e.target.value))
);
};
currently what is happening is as soon as I search on each individual column it refreshes the search on the present values
first You make a generic function and then implement every input text
field. This solution is especially in react js and js.
const searchByName = (name) => {
if (name !== "") {
console.log(name);
const res = data.filter((sd) => {
return (
sd.firstName.toString().toLowerCase().includes(search) ||
sd.email.toString().toLowerCase().includes(search)
);
});
console.log(res);
setData(res);
} else {
setData(dataFilter);
}
};

Sveltekit how do I set checkboxes checked based on query params?

I am trying to set checkboxes active based on query parameters using Sveltekit. To achieve this, I tried to get all route query parameters using the 'url.searchParams.entries()' method to get all query parameters from the URL.
Then I am trying to loop through all the params and then loop through all posts and check if the value of the query param is equal to a value in posts. If so, it should set checked to true forEach checkbox that meets the value. Then in my HTML, I bind the checked variable to my checkbox. But the issue is that when I put in 4 in the query params (or select 4 using the checkbox), it checks all the checkboxes but, if I select any of the other checkboxes, it doesn't do a single thing (besides from querying data from the JSON placeholder api)
This is my HTML:
<div class="grid grid-cols-2">
{#each posts as post}
<div class="col-span-1">
<input type="checkbox" bind:checked={checked} value={post.id} bind:group=
{selectedPosts} on:change="{() => updateValue(post.id)}" class="mr-2">
</div>
<div class="col-span-1">
<label for="{post.id}">{post.id}</label>
</div>
{/each}
</div>
This is inside my script tag:
import { filter, results } from '../../stores.js';
import { page } from '$app/stores';
let checked = false
let selectedPosts = []
const posts = [
{
name: 'post',
id:'1'
},
{
name: 'post',
id: '2'
},
{
name: 'post',
id: '3'
},
{
name: 'post',
id: '4'
}
]
$: {
//If the query params would be '?posts=1', the output would be ['posts', '1']
let params = [...$page.url.searchParams.entries()]
params.forEach(param => {
//Returns the first param. In this case '1'
let value = param[1]
posts.forEach(post => {
if(post.id === value){
console.log('true')
checked = true
} else {
checked = false
console.log('false')
}
})
});
}
async function updateValue(value) {
filter.set(value)
}
In my store I set the query params like so:
export const results = derived(filter, (value) => {
if(!value) return {};
const data = fetch(`https://jsonplaceholder.typicode.com/todos/${value}`).then(res => {
return res.json()
})
return data
});
filter.subscribe(value => {
if(!value) return
goto(`/activiteiten/filter?post=${value.toString()}`)
return value
})
And finally I return with a derived store some data from the JSON placeholder API.
You don't need bind:checked={checked} when using bind:group. I think this is the root of your problem. You are setting the same checked variable for every item.
if(post.id === value){
console.log('true')
checked = true
} else {
checked = false
console.log('false')
}
When you later check based on this variable, you get unexpected behavior.

How do you set multiple properties to be returned in Javascript-React?

I am trying to build a search box. When you type in it, it automatically filters my App.js file (Cards of robots).
render() {
const filteredRobots = this.state.robots.filter(robots => {
return robots.name.toLowerCase().includes(this.state.searchfield.toLowerCase())
})
return(
<div className='tc'>
<h1>RoboFriends</h1>
<SearchBox searchChange={this.onSearchChange}/>
<CardList robots={filteredRobots}/>
</div>
)
}
I have a separate, robots.js file in which I list the properties of the robots:
export const robots = [
{
id: 1,
name: 'Leanne Graham',
username: 'Bret',
email: 'Sincere#april.biz'
},
My filter method works, when I only put a single property in it. In the code above, I am illustrating it when it is filtered by name. I would like to include the "email" property as well, so that when I type in the search field, it also filters by the email and not just the name.
Thanks in advance, this is my first post, sorry for not being clear, I recently started learning.
You can combine the objects fields into a single string and use it instead of using the name
const filteredRobots = this.state.robots.filter(robot => {
return Object.values(robot).join(" ").toLowerCase().includes(this.state.searchfield.toLowerCase())
})
Now, all the robot fields (name, username, email, id) are considered in your search function.
filter method passes the array items directly.
const searchedString = this.state.searchfield.toLowerCase()
const filteredRobots = robots.filter(robotItem => robotItem.name.toLowerCase().includes(searchedString) || robotItem.username.toLowerCase().includes(searchedString) )
more about the filter method in mdn docs

Merging existing localstorage item with state for a shoppingcart

I got a situation where I do not have the experience to know which method is the best and what im doing wrong. The situation is as following:
I got a page with products which have a input + order button, which will add the order to the shoppingcart. My thought was to first set the state for each order you make:
const [amountItem, setAmountItem] = useState({
product: {
id: '',
amount: ''
}
});
Updating:
function handleChange(evt, id) {
const value = evt.currentTarget.value;
setAmountItem({
...amountItem,
product:{
id: id,
amount: value
}
});
console.log(amountItem);
}
Which then I push to the shoppingcart/checkout page (no modal):
if (e.target[0].value < productItem.stock) {
history.push({
pathname: `/winkelwagen/`,
state: {data: amountItem}
});
On this page, i first check if location.state exists before using the shoppingcart component:
if (location.state !== null && shoppingCartItems === '') {
console.log(location.state.data);
setShoppingCartItems(location.state.data);
setShoppingCartActive(true);
let cartString = JSON.stringify(shoppingCartItems);
localStorage.setItem('shopping_carts', cartString)
}
When it does exist, some product is ordered with an amount and must be set to localstorage, the product is 'always' visible when refreshing, etc. Until this point it works, the localstorage item exists:
(key)shopping_carts (value){"product":{"id":3,"amount":"2"}}
After that comes the shoppingcart component:
<ShoppingCart
shoppingCartItems={shoppingCartItems}
setShoppingCartItems={setShoppingCartItems}
shoppingCartActive={shoppingCartActive}
setShoppingCartActive={setShoppingCartActive}
/>
This is where my problem starts. Long story short, it only shows the single item from the state, which obviously will be gone.
In this file I got a useEffect part for the localstorage:
useEffect(() =>{
let shoppingCart = localStorage.getItem("shopping_carts");
console.log('shoppingcartitems ');
shoppingCart = JSON.parse(shoppingCart);
console.log(shoppingCart);
if (shoppingCart !== "") {
const id = shoppingCartItems.id;
const amount = shoppingCartItems.amount;
//setShoppingCartItems(shoppingCart)
setShoppingCartItems(prevState => ({
...prevState,
product: {
...shoppingCartItems,
id: id,
amount: amount
}
}))
}
}, [setShoppingCartItems])
The output for 'shoppingCart' is <empty string>. Why is that? Is the format wrong? I'm also using the localstorage for other info, which works fine. I know the setShoppingCartItems is not correct for multiple values, but I wanted to test this single entry first.
Update:
const CheckoutPage = () => {
const location = useLocation();
const [shoppingCartItems, setShoppingCartItems] = useState('');
const [shoppingCartActive, setShoppingCartActive] = useState(false);
const [mode, setMode] = useState('init');
let savedShoppingCart = JSON.parse(localStorage.getItem("shopping_carts"));
console.log('saved shopping cart: ')
console.log(savedShoppingCart);
if (savedShoppingCart !== "" && mode === 'init') {
const id = savedShoppingCart.id;
const amount = savedShoppingCart.amount;
//setShoppingCartItems(shoppingCart)
setShoppingCartItems(prevState => ({
...prevState,
product: {
...shoppingCartItems,
id: id,
amount: amount
}
}))
setMode('data');
//setShoppingCartActive(true);
}
if (location.state !== null && shoppingCartItems === '') {
console.log(location.state.data);
setShoppingCartItems(location.state.data);
setShoppingCartActive(true);
let cartString = JSON.stringify(shoppingCartItems);
localStorage.setItem('shopping_carts', cartString)
}
return (
<div className="shoppingCartPage">
<ShoppingCart
shoppingCartItems={shoppingCartItems}
setShoppingCartItems={setShoppingCartItems}
shoppingCartActive={shoppingCartActive}
setShoppingCartActive={setShoppingCartActive}
/>
</div>
)
}
So basically I want to do 3 things here:
Get the data from the localstorage item
Is there a saved localstorage item? Add it to existing shoppingCartItems (prevstate)
Save the updated (or new when no localstorage item exists) shoppingCartItems after that
After that I want to pass the data to the shoppingcart where i can increase/decrease items or remove/splice the values.
Treat useEffect with caution as an eventListener on React state.
Therefore you need to specify in the dependency array everything might change, in order to trigger the useEffect callback.
In your useEffect dependencies, where you are updating your shoppingCartItems, you have added only setShoppingCartItems - which I assume that its a setState function. This results in your useEffect te be called only once at the app start because setState functions never change.
So, to have your shoppingCartItems updated via useEffect you need to add it to dependencies.
useEffect(() => {
// your code
}, [setShoppingCartItems, shoppingCartItems])
This may fix your problem, because you never call logic that saves update shopping cart state, the second time, therefore you get empty in your console log.

Categories

Resources