I am having a trouble where an array of Objects are returning [Object object]. What could be the missing fix to get the value of product from the mapped targeted values.
this is my sample array.
const product = [{food:'BREAD',price: 6}]
this is where I map the values and get the targeted value.
<Form >
{product.map((item, index) => (
<div key={index} className="mb-3">
<Form.Check
input value={[item]}
id={[item.food]}
type="checkbox"
label={`${item.food}`}
onClick={handleChangeCheckbox('PRODUCTS')}
/>
</div>
))}
</Form>
this handles the e.target.value from checked checkboxes.
const handleChangeCheckbox = input => event => {
var value = event.target.value;
var isChecked = event.target.checked;
setChecked(current =>
current.map(obj => {
if (obj.option === input) {
if(isChecked){
return {...obj, chosen: [...obj.chosen, value ] };
}else{
var newArr = obj.chosen;
var index = newArr.indexOf(event.target.value);
newArr.splice(index, 1); // 2nd parameter means remove one item only
return {...obj, chosen: newArr};
}
}
return obj;
}),
);
console.log(checked);
}
finally, this is where I am having problems. Chosen is returning [Object object]console.log(checked).
const [checked, setChecked] = useState([
{ option: 'PRODUCTS',
chosen: [],
}
]);
What do I insert inside chosen:[] to read the following arrays. Im expecting to see
0:
food: 'bread'
price: '6'
Thank you so much for helping me!
Html input value prop is a string, and it's change event target value is also string.
Here you are passing an object to the value prop, which will be stringified as [Object object].
Instead, update your change handler to take item instead of event.
const handleChangeCheckbox = (input) => (value) => {
setChecked((current) => {
// Value is checked if it exists in the current chosen array
const isChecked = current.chosen.find((item) => item.food === value.food) !== undefined;
// Remove it from state
if (isChecked) {
return {
...current,
chosen: current.chosen.filter((item) => item.food === value.food),
};
}
// Add it to state
return {
...current,
chosen: [...current, value],
};
});
};
Then update your input element onChange handler, to call your handler with the item itself, instead of the event.
onClick={() => handleChangeCheckbox('PRODUCTS', item)}
I don't know what the props for your component Form.Check are. But, I would expect an input type="checkbox" to have a checked prop.
A checkbox is checked if the item is in the chosen state array.
<Form>
{product.map((item, index) => (
<div key={item.food} className="mb-3">
<Form.Check
type="checkbox"
id={item.food}
label={item.food}
checked={checked.chosen.find((chosen) => chosen.food === item.food) !== undefined}
onClick={() => handleChangeCheckbox('PRODUCTS', item)}
/>
</div>
))}
</Form>
Hmm, don't you need to inline your handleChangeCheckbox function? As otherwise it's just getting executed. So instead onClick={handleChangeCheckbox('PRODUCTS')} do onClick={(event) => handleChangeCheckbox('PRODUCTS', event)}.
Then your handleChangeCheckbox function will start handleChangeCheckbox = (input, event) => {...}
Related
I want to add data and see in below, and also when I start app, I want see added records. But I can see it, when I'm try to writing something in the fields.
The thing is, the function that updates the static list is asynchronous. This function retrieves data from the database, but before assigning it to a variable, the page has been rendered. There is some way to wait for this variable or update information other way than when you try to type it in the fields. This is before the form is approved.
[![enter image description here][1]][1]
class AddAdvertisment extends React.Component <any, any> {
private advertisment;
constructor(props, state:IAdvertisment){
super(props);
this.onButtonClick = this.onButtonClick.bind(this);
this.state = state;
this.advertisment = new Advertisement(props);
}
onButtonClick(){
this.advertisment.add(this.getAmount(), this.state.name, this.state.description, this.state.date);
this.setState(state => ({ showRecords: true }));
}
updateName(evt){
this.setState(state => ({ name: evt.target.value }));
}
....
render() {
return (<React.Fragment>
<div className={styles.form}>
<section className={styles.section}>
<input id="name" onChange={this.updateName.bind(this)} ></input>
<input id="description" onChange={this.updateDescription.bind(this)} ></input>
<input type="date" id="date" onChange={this.updateDate.bind(this)} ></input>
<button className={styles.action_button} onClick={this.onButtonClick.bind(this)}>Add</button>
</section>
</div>
{<ShowAdvertismentList/>}
</React.Fragment>
);
}
class ShowAdvertismentList extends React.Component <any, any>{
render(){
let listItems;
let array = Advertisement.ad
if(array !== undefined){
listItems = array.map((item) =>
<React.Fragment>
<div className={styles.record}>
<p key={item.id+"a"} >Advertisment name is: {item.name}</p>
<p key={item.id+"b"} >Description: {item.description}</p>
<p key={item.id+"c"} >Date: {item.date}</p>
</div>
</React.Fragment>
);
}
return <div className={styles.adv_show}>{listItems}</div>;
class Advertisement extends React.Component {
public static ad:[IAdvertisment];
constructor(props){
super(props);
if(!Advertisement.ad){
this.select_from_db();
}
}
....
select_from_db = async () => {
const res = await fetch('http://localhost:8000/select');
const odp = await res.json();
if(odp !== "brak danych")
odp.forEach(element => {
if(Advertisement.ad){
Advertisement.ad.push(element);
}
else{
Advertisement.ad = [element];
I try to create function and child like:
function Select_from_db(){
const[items, setItems] = useState();
useEffect(() => {
fetch('http://localhost:8000/select')
.then(res => res.json())
.then(data => setItems(data));
}, []);
return <div className={styles.adv_show}>{items && <Child items={items}/>}
</div>;
}
function Child({items}){
return(
<>
{items.map(item => ( ...
))}
</>
And is working good in first moment, but if I want add item to db I must refresh page to see it on a list below.
I use is instead ShowAdvertismentList in render function. Elements be added to db but not showing below. In next click is this same, until refresh page.
And in my opinio better use a list, becouse I musn't want to conect to database every time to download all records.
[1]: https://i.stack.imgur.com/IYSNU.gif
I now recipe. I must change state on componentDidMount in AddAdvertisment class.
async componentDidMount(){
let z = await setTimeout(() => {
this.setState(state => ({ loaded: true}));
}, 1000);
}
render() {
return (<React.Fragment >
(...)
{this.state.loaded ? <ShowAdvertismentList /> : <Loading/>}
</React.Fragment>
);
}
I am a novice MERN stack developer.
I am trying to calculate the number of pages for pagination. The info object prints in console.log. However, when I try to use it in the for loop I get an error.
Can someone please explain what's the React logic or flow behind this? I have had issues with this multiple times but, could fix it with conditional rendering. But, somehow I wasn't able to fix this and I don't seem to understand the logic of how the flow in react is.
App Component :
const App = () => {
const [episodes, setEpisodes] = useState({});
const [loading, setLoading] = useState(false);
const [currentPage, setCurrentPage] = useState(1);
const [episodesPerPage, setEpisodesPerPage] = useState(10);
useEffect(() => {
const fetchEpisodes = async () => {
setLoading(true);
const res = await axios.get('https://rickandmortyapi.com/api/episode/');
setEpisodes(res.data);
setLoading(false);
};
fetchEpisodes();
}, []);
console.log(episodes.info);
return (
<div>
<div id='header'>
<h1>Rick & Morty</h1>
<h2>Episodes</h2>
</div>
<div>
<h3>All Episodes</h3>
<EpisodeList episodeList={episodes.results} loading={loading} />
<Pagenation info={episodes.info} />
</div>
</div>
);
};
export default App;
Pagenation Component:
const Pagenation = ({ info }) => {
const pageNumbers = [];
console.log(info);
for (let i = 1; i <= Math.ceil(info.count / 20); i++) {
pageNumbers.push(i);
}
return (
<nav aria-label='...'>
<ul class='pagination pagination-lg'>
{pageNumbers.map((number) => {
return (
<li class='page-item active' aria-current='page'>
<span class='page-link'>
{number}
<span class='sr-only'>(current)</span>
</span>
</li>
);
})}
</ul>
</nav>
);
};
Conditional rendering can be the solution here as well.
episodes is initially an empty object, so episodes.info is initially undefined. This means you cannot access a property on info without checking if it exists first because you know already that it will be undefined at the beginning.
A simple solution might look like this:
{episodes.info && <Pagenation info={episodes.info} />}
You could also move the conditional into the Pagenation component to be something like this:
if (info) {
for (let i = 1; i <= Math.ceil(info.count / 20); i++) {
pageNumbers.push(i);
}
}
Regardless of your strategy to avoid the error, the core of the issue is that you have data that is loaded after the component mounts. This means you need to account for that data being missing for at least one render.
I manage a list of related elements in my form with a MUIDataTable(encapsulated here as CrudList) and a MUI Autocomplete.
I managed to add new elements through the autocomplete components onChange and to remove an element from a button using almost the same code. But I need to add .value on the second case Or it doesn't re-render.
What I'm doing wrong?
function RelatedModels({name, value ,model, tittle, columns, optionsSelector, onChange, ...fc}) {
const formik = useFormikContext();
const options = useSelector(createSelector(optionsSelector,
elements=> elements.filter(item => ! value.some(s=> item.idx === s.idx)))
);
const buttons = [
quickButton(
idx => () => {
const a =fc;
debugger;
//THIS NOT RE ENDER
formik.values[name]= value.filter(elem => idx !== elem.idx);
formik.setFieldTouched(name, true, false);
}
, 'Eliminar', <Delete/>)
];
return (
<Paper className="formPanel">
<h1>{tittle}</h1>
<Autocomplete
options={options}
onChange={(o, newElement)=> {
// THIS RE RENDER THE COMPONENT
formik.values[name].value = value.push(newElement);
formik.setFieldTouched(name, true, false);
}}
renderOption={ (option, state) =>
<span>{option.name}</span>
}
renderInput={params =>(
<MuiTextField {...params} label="Select to add" margin="normal" fullWidth/>)
}
/>
<CrudList Model={model} columns={columns.concat(buttons)} elements={value} buttons/>
</Paper> );
}
I include the component in the Formik as Follows
<Field as={RelatedModels}
name="accessories" model={Accessory} optionsSelector={availableAccessories}
tittle="Selecciona accesorio a aƱadir"
columns={accessoriesColumns}
/>
Hello I am working on a process with React that will allow users to select a row or rows from a table by selecting check-boxes.
I need assistance with how once a row is checked, how can I store this information but at the same time if the row is unchecked I would also want to update the state.
Than when the user selects the submit button it will send the array object to the server side.
I have an empty array in my state and in the method that handles selecting a checkbox I am attempting to push the data to the array and than send the array with a form.
It appears as if the array is not being updated or I am missing something?
class TestStatus extends Component {
constructor (props) {
super(props)
this.state = {
selected: []
}
handleCheckChildeElement = (event) => {
var data = this.global.data;
data.forEach(data => {
if(data.testid === event.target.value) {
data.isChecked = event.target.checked
if(event.target.checked === true) {
this.setState({ selected: [ ...this.state.selected, data]
});
}
console.log(this.state.selected);
}
});
this.setGlobal({ data });
}
handleSubmit(event) {
event.preventDefault();
axios.post('http://localhost:5000/api/advanced_cleanup',
this.state.selected)
.then((res) => {
console.log("Sending tests");
}).catch(event => console.log(event));
}
render() {
return(
<div>
<table>
<AdvancedRows checked={this.handleCheckChildeElement}
handleCheckChildeElement={this.handleCheckChildeElement}/>
</table>
<form className="ui form" onSubmit={this.handleSubmit}>
<button
className="ui basic blue button" type="submit"
style={{ marginBottom: '5em' }}>
Submit
</button>
</form>
</div>
);
}
}
I expect to be able to select a checkbox or multiple and update the state array based on what is checked and than send that data to the server side.
After some additional research online I found the correct way with react to update the state array and than update it upon unchecking a check box.
If the targeted row is checked it will pass that rows object into the state array otherwise if the check box of the row is unchecked it will iterate over the state array and filter out the item that was unchecked.
This is the guide I used to assist me. https://scriptverse.academy/tutorials/reactjs-update-array-state.html
if(event.target.checked === true) {
this.setState({ selected: [...this.state.selected, data ] });
} else {
let remove = this.state.selected.map(function(item) {
return item.testid}).indexOf(event.target.value);
this.setState({ selected: this.state.selected.filter((_, i) => i !== remove) }); }
Expanding on my comment above.
handleCheckChildeElement = (event) => {
var data = this.global.data;
// create an empty array so that each click will clean/update your state
var checkedData = [];
data.forEach(data => {
if(data.testid === event.target.value) {
data.isChecked = event.target.checked
if(event.target.checked === true) {
// instead of setting your state here, push to your array
checkedData.push(data);
}
console.log(checkedData);
}
});
// setState with updated checked values
this.setState({selected: checkedData});
this.setGlobal({ data });
}
I am working on a project in React. The idea is that when you search an artist an img render on the pg. Once you click the image a list of collaborating artists is rendered. You can then click a name and see that persons collabpratign artists. Here is my issue: Rather than the state clearing/resetting each time a new artist is clicked, new artists just add on to the original state. Can someone help me figure out how to clear the state so that the state clears and returns a new list of collaborators? Been stuck on this for hours. Here is the code
searchForArtist(query) {
request.get(`https://api.spotify.com/v1/search?q=${query}&type=artist`)
.then((response) => {
const artist = response.body.artists.items[0];
const name = artist.name;
const id = artist.id;
const img_url = artist.images[0].url;
this.setState({
selectedArtist: {
name,
id,
img_url,
},
});
})
.then(() => {
this.getArtistAlbums();
})
.catch((err) => {
console.error(err);
});
}
getArtistCollabs() {
console.log('reached get artist collab function');
const { artistCounts } = this.state;
// console.log(artistCounts);
const artist = Object.keys(artistCounts).map((key) => {
//kate
const i = document.createElement("div");
i.innerHTML = key;
i.addEventListener('click', () => {
this.searchForArtist(key);
})
document.getElementById("collabs").appendChild(i);
});
this.setState({});
}
//kate
renderArtists() {
const artists = this.getArtistCollabs();
}
render() {
const img_url = this.state.selectedArtist.img_url;
return (
<div>
<form onSubmit={this.handleSubmit}>
<input type='text' name='searchInput' className="searchInput" placeholder="Artist" onChange={this.handleChange} />
<input type='submit' className="button" />
</form>
<img className="artist-img" src={this.state.selectedArtist.img_url}
// kate
onClick={this.renderArtists} alt="" />
<div id="collabs">
</div>
</div>
Your problem is right here:
const artist = Object.keys(artistCounts).map((key) => {
//kate
const i = document.createElement("div");
i.innerHTML = key;
i.addEventListener('click', () => {
this.searchForArtist(key);
})
document.getElementById("collabs").appendChild(i);
What you have done here is manually create html elements and insert them into the dom. As soon as this takes place react has no control over these newly created elements. You should only manipulate the DOM like this when its absolutely necessary. Instead you should be making a new component called something like <ArtistCollaborators> and it should take in the artists as props and be what renders the code you have here into the DOM using its own render method.
This will be the React way of doing it, and allows react to be fully control of what you are rendering into the DOM.