I have a parent component that contains two arrays
newChoiceArray: [
{ id: 1, text: '1', questionId: 'favourite number?', value: '1' },
{ id: 2, text: '2', questionId: 'favourite number?', value: '2' },
{ id: 3, text: '3', questionId: 'favourite number?', value: '3' },
],
ChoiceArray: [
{ id: 4, text: 'red', questionId: 'favourite colour?', value: '1' },
{ id: 5, text: 'blue', questionId: 'favourite colour?', value: '4' },
],
}
I have a component that renders a button for each object inside of an array
const MultiChoiceQuestions = props => {
const { multiChoiceArray, handleClick } = props
return (
<div>
{multiChoiceArray.map(questionChoice => {
return (
<button type="button" key={questionChoice.id} onClick={handleClick}>
{questionChoice.text}
</button>
)
})}
</div>
)
}
When I render my child component, I can pass an array as a prop
<MultiChoiceQuestions handleClick={this.testClick} multiChoiceArray={newChoiceArray} />
<MultiChoiceQuestions handleClick={this.testClick} multiChoiceArray={ChoiceArray} />
When I click the button, I want to see which object inside of that array is being selected.
testClick = event => {
event.preventDefault()
console.log(event.currentTarget)
}
Instead of outputting this <button type="button">3</button>
It should output this { id: 3, text: '3', questionId: 'favourite number?', value: '3' },
you can pass the object as button value, for example:
{multiChoiceArray.map(questionChoice => {
return (
<button type="button" key={questionChoice.id} value={JSON.stringify(questionChoice)} onClick={handleClick}>
{questionChoice.text}
</button>
)
}
and then you can catch this, using property value from currentTarget:
testClick = event => {
event.preventDefault()
console.log(JSON.parse(event.currentTarget.value))
}
I don't know if is the best approach, but I know that works.
UPDATE
I was wondering about this question, will you use something else from event object ? else you can pass directly the item into the function:
{multiChoiceArray.map(questionChoice => {
return (
<button type="button" key={questionChoice.id} onClick={() => handleClick(questionChoice)}>
{questionChoice.text}
</button>
)
}
// parent file
testClick = obj => {
console.log(obj)
}
Related
I want to make a filter system using multiple checkbox. But when i checked one checkbox it filter the state but when i unchecked it how i can get back the all data in state . Also if i select multiple checkbox then it will filter from the filtered item.
Here is my code.
state = {
restaurant : [
{name: 'La mesa', cuisine: ['italian', 'indian']},
{name: 'Red Bull', cuisine: ['chiness', 'french']}
{name: 'Purnima', cuisine: ['thai', 'arabic']}
]
cuisine: [
{id: 1, name: 'italian'},
{id: 2, name: 'indian'},
{id: 3, name: 'chiness'}
{id: 4, name: 'french'},
{id: 4, name: 'arabic'},
]
}
handleCuisineFilter = (e) => {
if (e.target.checked) {
const filter =
this.state.restaurant.length &&
this.state.restaurant.filter((rest) => rest.cuisine.includes(e.target.value));
this.setState({ restaurant: filter });
} else {
Now when unchecked how i can get previous state???
}
};
render() {
return (
<div>
{this.state.cuisine.length && this.state.cuisine.map(
cuisine=> (<li>
<input
id={cuisine.id}
type='checkbox'
onChange={this.handleCuisineFilter}
name='check'
value={cuisine.name}
/>
{cuisine.name } {here will be count of number of restaurant}
</li>
))}
{this.state.restaurant.length && this.state.restaurant.map(rest=> <h5>rest.name</h5>)}
</div>
I tried to explain best via my code . Help me please. Thank you in advance
You have to keep track of checked state for each filter and then filter against all filters at once every time.
Here is the solution
EDIT
import React, { Component } from "react";
import "./App.css";
class App extends Component {
state = {
restaurant: [
{ name: "La mesa", cuisine: ["italian", "indian"] },
{ name: "Red Bull", cuisine: ["chiness", "french"] },
{ name: "Purnima", cuisine: ["thai", "arabic"] },
],
// maintain a checked state for each filter
cuisine: [
{ id: 1, name: "italian", checked: false },
{ id: 2, name: "indian", checked: false },
{ id: 3, name: "chiness", checked: false },
{ id: 4, name: "french", checked: false },
{ id: 5, name: "arabic", checked: false },
],
};
setFilter = (cuisine, flag) => {
this.setState((prevState) => ({
cuisine: prevState.cuisine.map((c) =>
// check state for the selected cuisine
c.id === cuisine.id ? { ...c, checked: flag } : c
),
}));
};
handleCuisineFilter = (e, cuisine) => {
if (e.target.checked) {
this.setFilter(cuisine, true);
} else {
this.setFilter(cuisine, false);
}
};
filterRestaurants = (restaurant) => {
const checkedFilters = this.state.cuisine.filter((c) => c.checked);
const noFiltersChecked = checkedFilters.length === 0;
if (noFiltersChecked) {
return true;
} else {
// EDITED:
const tmp = checkedFilters.reduce(
(hasRestaurantAllTheseCuisines, nextCuisine) =>
(hasRestaurantAllTheseCuisines =
hasRestaurantAllTheseCuisines &&
restaurant.cuisine.includes(nextCuisine.name)),
true
);
return tmp;
}
};
render() {
return (
<div>
{this.state.cuisine.length &&
this.state.cuisine.map((cuisine) => (
<li key={cuisine.id}>
<input
id={cuisine.id}
type="checkbox"
onChange={(e) => this.handleCuisineFilter(e, cuisine)}
name="check"
value={cuisine.name}
/>
{cuisine.name} {/* here will be count of number of restaurant */}
</li>
))}
{/* Use .filter() with cuisine state */}
{this.state.restaurant.length &&
this.state.restaurant
.filter(this.filterRestaurants)
.map((rest) => <h5 key={rest.name}>{rest.name}</h5>)}
</div>
);
}
}
export default App;
Edited the code. The only change was the filter check here
...
const tmp = checkedFilters.reduce(
(hasRestaurantAllTheseCuisines, nextCuisine) =>
(hasRestaurantAllTheseCuisines =
hasRestaurantAllTheseCuisines &&
restaurant.cuisine.includes(nextCuisine.name)),
true
);
...
i have the data structure like below,
const item = {
id: '1',
orders: [
{
id: '1',
title: 'order-1',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
}
],
subItems: [
{
id: '1',
title: 'subitem-one',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '1',
title: 'subitem1-order-one',
status: 'new',
},
{
id: '2',
title: 'subitem1-order-two',
status: 'new',
},
]
},
{
id: '2',
title: 'subitem-two',
status: 'new',
startDate: '2020-08-13T00:00:00.000Z',
orders: [
{
id: '2',
title: 'subitem2-order-one',
status: 'new',
},
},
I have to display each subitem name from above data in each card in a list.
below is how it should look in a list.
below is my code,
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
//how should i map the items data to loop through each subitem and display it as in the picture above.
);
}
I am not sure how to loop through each subitem and display its name in a card using javascript and react.
could someone help me with this. thanks.
Ciao, assuming that you are using Card component from material ui you could do something like:
import { Card, CardHeader} from '#material-ui/core';
function Parent({items}: Props) {
//items is the same data as mentioned above
return (
items.subItems.map(el => {
<Card>
<CardHeader
title={el.title}
/>
</Card>
})
);
}
I'm assuming that Parent is a React functional component, so you can return the data in this way,
function Parent({items} : Props) {
return (
<div>
{
items.subItems.map(function (subItem) {
return <div>{subItem.title}</div>;
});
}
</div>
)
}
The template is shown below:
const Parent = () => {
const data = [...] // the data must be an array
return data.map(child => <Child data={child} />)
}
I have a nested array and I would like to render this array with JSX code such that key like array1 should be display once and the text should be displayed as list and then continue the same loop with the next array. I have tried using map function and for loop but could not achieve success.
sampleArray : [{"array1": [ {"text": "abc"},{"text": "def"}, {"text": "ghi"}],
"array2":[{"text": "efg"}, {"text": "fgh"}]]
Please suggest me map function to iterate over this array to render into JSX code. Thanks
Hey I don't know if you made a mistake in your object, but here are two versions of this implementation with your object and with my update:
Ignore typings did it in TypeScript
export const Test = ({ className }: Test) => {
const sampleArray = [
{
array1: [{ text: 'abc' }, { text: 'def' }, { text: 'ghi' }],
array2: [{ text: 'efg' }, { text: 'fgh' }],
},
]
const sampleArray2 = [
{
array1: [{ text: 'abc' }, { text: 'def' }, { text: 'ghi' }],
},
{
array2: [{ text: 'efg' }, { text: 'fgh' }],
},
]
return (
<>
{/* YOUR VERSION */}
<div>
{Object.keys(sampleArray[0]).map((key) => {
return (
<div>
<div id="title">{key}</div>
{sampleArray[0].map((item) => {
return <div>{item.text}</div>
})}
</div>
)
})}
</div>
{/* UPDATED VERSION */}
<div>
{sampleArray2.map((key) => {
const title = Object.keys(key)[0]
return (
<div>
<div id="title">{title}</div>
{key[title].map((item) => {
return <div>{item.text}</div>
})}
</div>
)
})}
</div>
</>
)
}
I'm using the react-sortablejs library.
When trying to move cards within the list. I get the error:
Cannot read property 'map' of undefined
I have a dense structure and it gets lost here. How to handle onChange so that I can see in the console that the order of the notes within the list has changed.
Demo here
import Sortable from 'react-sortablejs';
// Functional Component
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
console.log(order)
onChange(order);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
class App extends React.Component {
state = {
item: {
id: "abc123",
name: "AAA",
lists: [
{
id: "def456",
list_id: "654wer",
title: 'List1',
desc: "description",
listItems: [
{
id: "ghj678",
title: "ListItems1",
listItemsId: "88abf1"
},
{
id: "poi098",
title: "ListItems2",
listItemsId: "2a49f25"
},
{
id: "1oiwewedf098",
title: "ListItems3",
listItemsId: "1a49f25dsd8"
}
]
},
{
id: "1ef456",
list_id: "654wer",
title: 'List 2',
desc: "description",
listItems: [
{
id: "1hj678",
title: "ListItems4",
listItemsId: "18abf1"
},
{
id: "1oi098",
title: "ListItems5",
listItemsId: "1a49f25"
},
{
id: "1oiwewe098",
title: "ListItems6",
listItemsId: "1a49f25dsd"
}
]
},
{
id: "2ef456",
title: 'List 3',
list_id: "254wer",
desc: "description",
listItems: [
{
id: "2hj678",
title: "ListItems7",
listItemsId: "28abf1"
},
{
id: "2oi098",
title: "ListItems8",
listItemsId: "234a49f25"
},
{
id: "df098",
title: "ListItems9",
listItemsId: "1asd8"
}
]
}
]
}
};
render() {
const c = this.state.item['lists'].map(item => { return item.listItems});
return (
this.state.item['lists'].map(item => {
return (<div>
{item.title}
<SortableList
key={uniqueId()}
items={item}
onChange={(item) => {
console.log(item)
this.setState({item});
}}
>
</SortableList>
</div>)
})
)
}
};
Thanks in advance.
You have to update few changes in your code.
Update the SortableList function as below.
First pass data-id={val.id} in li and after that in onChange method you will receive the order with id. So based on that we are sorting the records.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
onChange={(order, sortable, evt) => {
items.listItems.sort(function(a, b){
return order.indexOf(a.id) - order.indexOf(b.id);
});
onChange(items);
}}
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val.id}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
Update the onChange event of App component.
onChange={(item) => {
let itemObj = {...this.state.item};
itemObj.lists.map(x=>{
if(x.id === item.id) x = item;
});
this.setState({itemObj});
}}
That's it!
Here is the working demo for you
https://stackblitz.com/edit/react-sortablejs-blzxwd
When remove the onChange event in the Sortable list, Its works.
const SortableList = ({ items, onChange }) => {
return (
<div>
<Sortable
tag="ul"
>
{items.listItems.map(val => {
return <li key={uniqueId()} data-id={val}>List Item: {val.title}</li>})
}
</Sortable>
</div>
);
};
I have a dropdown list with 5 options. I need to save the selected option to my state as listValue.
My list of options and the state
const options = [
{ key: 1, text: 'OK', value: 1 },
{ key: 2, text: 'Avvikelse', value: 2 },
{ key: 3, text: 'Ej Relevant', value: 3 },
{ key: 4, text: 'Observation', value: 4 },
{ key: 5, text: 'Saknas', value: 5 },
]
export default class ConfirmationModal extends React.Component {
state = {
listValue: 'Status'
}
My list (from semantic-ui)
dropDownList = () => (
<Dropdown
placeholder={this.state.listValue}
clearable
options={options}
selection
/>
)
How can I store the selected option in my state?
You can add an onChange handler and put the value given to the handler in your component state.
Example
const options = [
{ key: 1, text: "OK", value: 1 },
{ key: 2, text: "Avvikelse", value: 2 },
{ key: 3, text: "Ej Relevant", value: 3 },
{ key: 4, text: "Observation", value: 4 },
{ key: 5, text: "Saknas", value: 5 }
];
class DropdownExampleControlled extends React.Component {
state = {
options,
value: options[0].value
};
handleChange = (_e, { value }) => this.setState({ value });
render() {
const { value, options } = this.state;
const currentOption = options.find(o => o.value === value);
return (
<Grid columns={2}>
<Grid.Column>
<Dropdown
onChange={this.handleChange}
options={options}
placeholder="Choose an option"
selection
value={value}
/>
</Grid.Column>
<Grid.Column>
<Segment secondary>
<pre>Current value: {currentOption.text}</pre>
</Segment>
</Grid.Column>
</Grid>
);
}
}
As I understood you, you need to save in the state the values, which user selected?
If yes, You need have an event for example onChange, which means that user seelct that particular option from list. and set it in state
onChange(selectedValue) {
this.setState({listValue: selectedValue});
}
add this function to your component:
handleChange = (_p, { value }) => {
this.setState({ listValue: value});
};
add it as prop to your Dropdown:
<Dropdown onChange={this.handleChange} placeholder={this.state.listValue} clearable options={options} selection />
Handle state management using setState. Simple example:
Example Sandbox
const options = [
{ key: 1, text: 'OK', value: 1 },
{ key: 2, text: 'Avvikelse', value: 2 },
{ key: 3, text: 'Ej Relevant', value: 3 },
{ key: 4, text: 'Observation', value: 4 },
{ key: 5, text: 'Saknas', value: 5 },
]
class App extends Component {
constructor(props){
super(props)
this.state = {
listValue: ''
}
}
componentWillMount() //before render
{
this.setState({
listValue: options[1].text //storing text from second line
})
}
render() {
return (
<div>
{this.state.listValue}
</div>
);
}
}
This displays: Avvikelse