React.js setState issue - javascript

I am learning React.js and I have a very strange issue. I follow the tutorial step by step, when I call this.setState to update the jokes array in this.state object with the modified one it doesn't change. I want to toggle the completed property to true / false on checkbox click. There is no console error.
Any opinion is welcome.
JokesTemplate.js
function JokeTemplate(props){
return (
<div className="col-md-4">
<label>Joke {props.item.id}</label>
<p>Question {props.item.desc}</p>
<p>Answer: {props.item.ans}</p>
<input type="checkbox" checked={props.item.completed} onChange={() => props.handleChange(props.item.id)} />
</div>
);
}
export default JokeTemplate;
Jokes.js
import React from 'react';
import JokeTemplate from './JokeTemplate';
const jokes = [{
id:1,
desc: "Question 1",
ans: "Answer 1",
completed: false
},
{
id:2,
desc: "Question 2",
ans: "Answer 2",
completed: true
},
{
id:3,
desc: "Question 3",
ans: "Answer 3",
completed: false
}];
class Jokes extends React.Component{
constructor(){
super()
this.state = {
jokesLst: jokes
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(id){
this.setState(prevState => {
let updatedObj = prevState.jokesLst.map( item =>{
if(item.id === id){
item.completed = !item.completed;
}
return item;
})
return { jokesLst: updatedObj }
});
}
render(){
const jokesComponentArr = this.state.jokesLst.map( joke => <JokeTemplate key={joke.id} item={joke} handleChange={this.handleChange} />);
return (
<>
{jokesComponentArr}
</>
)
}
}
export default Jokes;
App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import NavBar from './components/NavBar';
import Jokes from './components/Jokes';
function App() {
return (
<div className="App">
<NavBar />
<header className="App-header">
<Jokes />
</header>
</div>
);
}
export default App;
Thanks in advance.

It seems your code still modifies the original elements in the array because they are objects which are not referenced by value. To eliminate the issue you need to copy each elements in your .map() call in your callback within prevState.
In handleChange you can try the following instead as:
this.setState(prevState => {
let updatedObj = prevState.jokesLst.map(item => {
const newItem = { ...item }
if (newItem.id === id) {
newItem.completed = !newItem .completed
}
return newItem
})
return { jokesLst: updatedObj }
})
See the difference with the extra const newItem = { ...item } line above.
Or you can use it even shorter:
this.setState(prevState => ({
...prevState,
jokesLst: prevState.jokesLst.map(item => ({
...item,
completed: item.id === id ? !item.completed : item.completed
}))
})

I think all you need to modify is only at the handleChange() method inside Jokes.js
I have never seen such way of putting logic to filter "item" and modify its "completed" field inside of this.setState() method. But I would suggest you to do it this way. So here we create a new instance of updatedObj, do all the logic for manipulating the completed field. and then finally just call setState and pass the updatedObj to it directly. I tested this on codesandbox, and it works.
handleChange(id) {
let updatedObj = this.state.jokesLst.map((item) => {
if (item.id === id) {
item.completed = !item.completed;
}
return item;
});
this.setState({
jokesLst: updatedObj
});
};

Related

Collect checkbox values as an array React

I have a checkbox component, I want my user to be able to check multiple items, and then the items to be saved in the state as an array.
If I select a checkbox my handleChange function seems to set my array to undefined, I'm not sure if it's the way I am sending the data or If I've setup my checkbox wrong, I'm quite new to React.
My main component is
export default class MainForm extends Component {
state = {
eventFormats: []
}
handleChange = input => event => {
this.setState({[input]: event.target.value})
console.log(this.state)
}
render() {
const eventFormat = {eventFormats: this.state.eventFormats}
return <EventFormat
nextStep={this.nextStep}
handleChange={this.handleChange}
values={eventFormat}
}
}
}
My event form component
export default class EventFormat extends Component {
state = {
eventFormats: [
{id: 1, value: 1, label: "Virtual", isChecked: false},
{id: 2, value: 2, label: "Hybrid", isChecked: false},
{id: 3, value: 3, label: "Live", isChecked: false},
]
}
saveAndContinue = (e) => {
e.preventDefault()
}
render() {
return (
<Form>
<h1 className="ui centered">Form</h1>
<Form.Field>
{
this.state.eventFormats.map((format) => {
return (<CheckBox handleChange={this.props.handleChange} {...format} />)
})
}
</Form.Field>
<Button onClick={this.saveAndContinue}>Next</Button>
</Form>
)
}
}
And finally my checkbox component
const CheckBox = (props) => {
return (<Checkbox label={props.label} onChange={props.handleChange('eventFormats')}/>)
}
export default CheckBox
The error is in your handleChange function, which sets state to a dictionary while you said you want the checkbox's value to be added to the eventFormats array in the state.
export default class MainForm extends Component {
state = {
eventFormats: []
}
handleChange = input => event => {
if (event.target.checked) {
this.setState({eventFormats: this.state.eventFormats.concat([event.target.value])});
} else {
const index = this.state.indexOf(event.target.value);
if (index === -1) {
console.error("checkbox was unchecked but had not been registered as checked before");
} else {
this.setState({eventFormats: this.state.eventFormats.splice(index, 1);
}
}
console.log(this.state)
}
render() {
const eventFormat = {eventFormats: this.state.eventFormats}
return <EventFormat
nextStep={this.nextStep}
handleChange={this.handleChange}
values={eventFormat}
}
}
}
There are a few things to fix:
this.setState({[input]: event.target.value})
this will always overwrite the array(eventFormats) with event.target.value.
<CheckBox handleChange={this.props.handleChange} {...format} />
in the above line, you're passing all the properties in each format object
const CheckBox = (props) => {
return (<Checkbox label={props.label} onChange={props.handleChange('eventFormats')}/>)
}
but here you're only using label and handleChange.
Here's a React StackBlitz that implements what you're looking for. I used <input type="checkbox" />, you can replace this with the Checkbox component you want. See the console logs to know how the state looks after toggling any of the checkboxes.
Also, added some comments to help you understand the changes.
const Checkbox = ({ id, checked, label, handleChange }) => {
return (
<>
<input
type="checkbox"
id={id}
value={checked}
// passing the id from here to figure out the checkbox to update
onChange={e => handleChange(e, id)}
/>
<label htmlFor={id}>{label}</label>
</>
);
};
export default class App extends React.Component {
state = {
checkboxes: [
{ id: 1, checked: false, label: "a" },
{ id: 2, checked: false, label: "b" },
{ id: 3, checked: false, label: "c" }
]
};
handleChange = inputsType => (event, inputId) => {
const checked = event.target.checked;
// Functional update is recommended as the new state depends on the old state
this.setState(prevState => {
return {
[inputsType]: prevState[inputsType].map(iT => {
// if the ids match update the 'checked' prop
return inputId === iT.id ? { ...iT, checked } : iT;
})
};
});
};
render() {
console.log(this.state.checkboxes);
return (
<div>
{this.state.checkboxes.map(cb => (
<Checkbox
key={cb.id}
handleChange={this.handleChange("checkboxes")}
{...cb}
/>
))}
</div>
);
}
}

How can I add a checkbox to each element in the list and to be able to control it through state in my react app?

I just finished an introductory course on React and now I am trying to make a react app where the user can add and remove items from a todo list. My trouble is when I try and add a checkbox to my program. I have tried to create a state that keeps track of the list items but I cant seem to figure out how to link the state to the items itself. Any tips on how I can add check boxes to my todo items would be greatly appreciated. Here is my App.js file:
import './App.css';
import React from "react"
import Todoitems from "./Todoitems"
class App extends React.Component {
constructor (props) {
super (props)
this.state = {
items: [],
numberOfItems: 0,
limitReached: false
}
this.addItem = this.addItem.bind(this)
}
addItem = (e) => {
if (this.state.numberOfItems < 10){
this.setState(prevState => {
return {numberOfItems: prevState.numberOfItems + 1}
})
if (this._inputElement !== "") {
let newItem = {
text: this._inputElement.value,
key: Date.now()
}
this.setState(prevState => {
return {
items: prevState.items.concat(newItem)
};
});
this._inputElement.value = "";
}
console.log(this.state.items);
console.log(this.state.numberOfItems);
} else {
this.setState({
limitReached: true
})
}
console.log(this.state.limitReached)
e.preventDefault();
}
render () {
return (
<div>
<Todoitems entries = {this.state.items}/>
<form onSubmit = {this.addItem}>
<input ref = {(a) => this._inputElement = a} placeholder = "enter task"></input>
{this.state.limitReached === false? <button type = "submit">Add</button>: <p>Maximum amount of items added</p>}
</form>
</div>
)
}
}
Here is my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
<App/>
</React.StrictMode>,
document.getElementById('root')
);
Let assume you have a checkbox in your TodoItem.
// todoItem.jsx
<input type='checkbox' checked={props.entry.checked} value={props.entry.checked} onChange={(e) => props.handleEntryCheck(e.value, props.index)} />
And you are looping through entries to show them like this:
// TodoItems.jsx
{
entries.map((entry, index) => <TodoItem index={index} entry={entry} handleEntryCheck={props.handleEntryCheck} /> )
}
In your App.jsx you can define handleEntryCheck like this:
const handleEntryCheck = (checked, index) => {
state.items[index].checked = checked
this.setState({
items: state.items.slice()
})
}
Later you can find out which items are selected:
const getSelectedItems = () => {
return state.items.filter(item => item.checked)
}
You can add state in newItem variable in addItem function like clicked below:
let newItem = {
text: this._inputElement.value,
key: Date.now(),
clicked: false
}
And add input tag in TodoItems component's mapping function inside for checkbox with onChange event having function like below :
<input type="checkbox" id={data.key} onChange = {(e) => {
let newItem = {
text: this.state.item[key].text,
key: this.state.item[key].key,
clicked: e.target.value
}
let newItems = this.state.items.splice(e.target.id, 1, newItem);
this.setState({
items: newItems
})
}} />
It's not easy to explain without code executor so I could give better advice if you give an URL of codesendbox.

How do I set state to toggle a boolean value that sits inside an array of JSON object?

I've been stuck on this today, and I've tried several possible solutions that didn't resolve the issue.
This is a flip-card effect I'm creating for a team's profile page. When user click on the profile-card it flips the card to show more info on the back. The way I've set up currently flips all the cards all at once when onClick is triggered, instead of the individual card. I know by doing that I need to set the current state of isTrue to render the boolean value from the JSON object, and I tried several possible ways I could think of with no succession.
I'd really appreciate if anyone can help me learn/understand how to solve this issue!
Here is the simplified example code:
JSON object:
data: [
{ id: 1, isTrue: false },
{ id: 2, isTrue: false },
{ id: 3, isTrue: false},
...
]
React Component:
import exampleData from 'data.js'
class App extends Component {
constructor () {
super()
this.state = {
isTrue: //I need to set the current state of isTrue to render from exampleData, but couldn't figure out how to do it.//
}
this.handleToggle = this.handleToggle.bind(this);
}
handleToggle (e) {
e.preventDefault();
this.setState(prevState => ({
isTrue: !prevState.isTrue
}))
}
render() {
return(
<div className="App">
{exampleData.data.map((obj) => {
return <ReactCardFlip isTrue={this.state.isTrue}/>
<button onClick={handleToggle}>Flip the card</div>
</ReactCardFlip>
})
</div>
);
}
}
export default App;
You need to store externalData in your component's state. Render this list using map and pass current clicked card to the toggle method. After this, you are able to change your state depending on the element you have clicked. See example below:
import exampleData from 'data.js'
class App extends Component {
constructor () {
super()
this.state = {
cards: [],
}
this.handleToggle = this.handleToggle.bind(this);
}
componentDidMount() {
this.state.setState({ cards: exampleData });
}
handleToggle (card) {
this.setState(prevState => ({
cards: prevState.cards.map(prevCard => {
if (prevCard.id === card.id) {
return {
id: prevCard.id,
isTrue: !prevCard.isTrue
}
}
return prevCard;
})}));
}
render() {
return (
<div className="App">
{this.state.data.map((card) => {
return (
<ReactCardFlip isTrue={card.isTrue}>
<button onClick={() => this.handleToggle(card)}>Flip the card</button>
</ReactCardFlip>
)
})}
</div>
);
}
}
export default App;
The main is each item should have its own isTure
So the single state isTrue cannot achieve your demand.
Two ways:
exampleData in state
isTure => arrIsTrue to correspond each item in exampleData
data: [
{ id: 1, isTrue: false },
{ id: 2, isTrue: false },
{ id: 3, isTrue: false},
...
]
these data can place in state
like after: this.state = { exampleData: exampleData.data }
so the render can be <ReactCardFlip isTrue={obj.isTrue}/>
also the handleToggle should get current toggle index to after:
<div className="App">
{this.state.exampleData.map((obj, index) => {
return <ReactCardFlip key={index} isTrue={this.state.isTrue}/>
<button onClick={() => handleToggle(index)}>Flip the card</div>
</ReactCardFlip>
})
</div>
and then in handleToggle to be:
handleToggle (index) {
const exampleData = this.state.exampleData
exampleData[index] = !exampleData[index].isTrue
this.setState({ exampleData: exampleData })
}
After all, don't forget key

How to clear input values of dynamic form in react

I have a dynamic form as a functional component which is generated via a class based component. I want to make reset button which clears the input field values and sets the state to null array.
Full code is available here:
https://codesandbox.io/s/beautiful-archimedes-o1ygt
I want to make a reset button, clearing all the input values and initializing the Itemvalues array to null.
Even if I set the values to null, it doesn't clear the input field.
However, the problem I'm facing is that since, it is a dynamic form and a functional component it doesn't have a predefined state for each individual form field making it difficult to set value to null.
Can someone please help, I'm stuck on this from a long time
Here's a codesandbox to show you how to reset the items: https://codesandbox.io/s/romantic-heisenberg-93qi7
I also left a note for you on how to get this to work with your API data, see the comment inside onChangeText()
The problem is that the inputs are not controlled by state as you have deduced. We should create an updated object for each item from your API, giving it a value prop.
index.js
import React from "react";
import ReactDOM from "react-dom";
import Cart from "./Cart";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
Items: [],
itemvalues: [{}]
};
this.onChangeText = this.onChangeText.bind(this);
this.getItems = this.getItems.bind(this);
this.handleReset = this.handleReset.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.findFieldIndex = this.findFieldIndex.bind(this);
this.trimText = this.trimText.bind(this);
}
getItems = () => {
/*if the data is coming from an API, store it in an array then .map() over it.
we can add a value prop to the object like:
so you can do something like:
const newItems = [...apiData].map((item) => {
return {
...item,
value: ""
}
})
this.setState({
Items: newItems
})
*/
this.setState({
Items: [
{
name: "item1",
description: "item1",
group: "groupA",
dtype: "str",
value: ""
},
{
name: "item2",
description: "item2",
group: "groupA",
dtype: "str",
value: ""
},
{
name: "item3",
description: "item3",
group: "groupB",
dtype: "str",
value: ""
},
{
name: "item4",
description: "item4",
group: "groupB",
dtype: "str",
value: ""
}
]
});
};
onChangeText = e => {
const updatedItems = [...this.state.Items].map(item => {
if (item.name === e.target.name) {
return {
...item,
value: e.target.value
};
} else {
return item;
}
});
const updatedItemValues = [...updatedItems].reduce((obj, curr) => {
if (!obj[curr.group]) {
obj[curr.group] = [];
}
obj[curr.group] = [...obj[curr.group], { [curr.name]: curr.value }];
return obj;
}, {});
this.setState({
...this.state,
Items: updatedItems,
itemvalues: updatedItemValues
});
};
findFieldIndex = (array, name) => {
return array.findIndex(item => item[name] !== undefined);
};
trimText(str) {
return str.trim();
}
handleReset = () => {
const resetedItems = [...this.state.Items].map(item => {
return {
...item,
value: ""
};
});
this.setState(
{
...this.state,
Items: resetedItems,
itemvalues: []
},
() => console.log(this.state)
);
};
handleSubmit = () => {
console.log(this.state.itemvalues);
};
render() {
return (
<div>
{
<Cart
Items={this.state.Items}
getItems={this.getItems}
handleSubmit={this.handleSubmit}
handleReset={this.handleReset}
onChangeText={this.onChangeText}
/>
}
</div>
);
}
}
Cart.js
import React, { useEffect } from "react";
import Form from "./Form";
const Cart = props => {
useEffect(() => {
props.getItems(props.Items);
}, []);
return (
<div>
<Form Items={props.Items} onChangeText={props.onChangeText} />
<button onClick={props.handleSubmit}>Submit</button>
<button onClick={props.handleReset}>Reset</button>
</div>
);
};
export default Cart;
The Cart component can remain mostly the same, we do not need to pass in props.items to useEffect() dependency.
Form.js
import React from "react";
const Form = props => {
return (
<div>
{props.Items.map(item => {
return (
<input
name={item.name}
placeholder={item.description}
data-type={item.dtype}
data-group={item.group}
onChange={e => props.onChangeText(e)}
value={item.value}
/>
);
})}
</div>
);
};
export default Form;
Now in Form component, we provide each input a value prop that is connected to the item our upper-most parent component-state.
That's pretty much all you need to reset the values.
See if that works for you:
Working example on CodeSandbox
Since you were already using hooks in part of your code, I've converted your class into a functional component using hooks (my advice: learn hooks and forget about class components).
I've added a value property to your INITIAL_STATE so it will keep the input value for each inputItem.
Full CODE:
index.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
import FormV2 from "./FormV2";
import "./styles.css";
function App() {
const INITIAL_STATE = [
{
name: "item1",
description: "item1",
group: "groupA",
dtype: "str",
value: "" // ADDED VALUE PROPERTY TO KEEP THE INPUT VALUE
},
{
name: "item2",
description: "item2",
group: "groupA",
dtype: "str",
value: ""
},
{
name: "item3",
description: "item3",
group: "groupB",
dtype: "str",
value: ""
},
{
name: "item4",
description: "item4",
group: "groupB",
dtype: "str",
value: ""
}
];
const [inputItems, setInputItems] = useState(INITIAL_STATE);
function handleChange(event, index) {
const newValue = event.target.value;
setInputItems(prevState => {
const aux = Array.from(prevState);
aux[index].value = newValue;
return aux;
});
}
function handleReset() {
console.log("Reseting Form to INITIAL_STATE ...");
setInputItems(INITIAL_STATE);
}
function handleSubmit() {
inputItems.forEach(item =>
console.log(
"I will submit input: " + item.name + ", which value is: " + item.value
)
);
}
return (
<FormV2
handleSubmit={handleSubmit}
handleReset={handleReset}
handleChange={handleChange}
inputItems={inputItems}
/>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
FormV2.js
import React from "react";
function FormV2(props) {
const formInputItems = props.inputItems.map((item, index) => (
<div key={item.name}>
{item.name + ": "}
<input
type="text"
data-type={item.dtype}
data-group={item.group}
placeholder={item.description}
value={item.value}
onChange={event => props.handleChange(event, index)}
/>
</div>
));
return (
<React.Fragment>
<form>{formInputItems}</form>
<button onClick={props.handleSubmit}>Submit</button>
<button onClick={props.handleReset}>Reset</button>
<div>State: {JSON.stringify(props.inputItems)}</div>
</React.Fragment>
);
}
export default FormV2;
In order to control the values of the child components (Items) which I presume are input fields you need to be passing down their values from their parent component. So each of your items will have an item.value which is stored in the parent component's state.
That means that in the parent component you will be able to define a method which clears all of the item values it is storing in its state.
That will probably look something like
resetInputs = () => {
this.setState({
inputFields: this.state.inputFields.map(inputField => {
...inputField,
value: ''
}
})
}
Also you'll need to write what kind of tag you want for your code to work, like input.
So what you'll end up with for the code of the child component you shared is something like:
const Form = (props) => {
return (
<div>
{props.Items.map(item => (
<input
name={item.name}
value={item.value}
placeholder={item.description}
onChange={e => props.onChangeText(e)}
/>
)
)}
</div>
);
}
export default Form
You want to manage the state of unknown number N of items, one way to achieve it is by managing a single object which contains all states, for example, setValuesManager manages N inputs and clicking the button reset its state:
function TextAreaManager() {
const [valuesManager, setValuesManager] = useState([...items]);
return (
<Flexbox>
{valuesManager.map((value, i) => (
<TextBoxItem
key={i}
value={value}
onChange={e => {
valuesManager[i] = e.target.value;
setValuesManager([...valuesManager]);
}}
/>
))}
<PinkButton
onClick={() =>
setValuesManager([...Array(valuesManager.length).fill('')])
}
>
Reset All
</PinkButton>
</Flexbox>
);
}
Demo:

Removing from react array

How do I remove an item from an array in react? I've tried a couple of things and it didnt work out. Just trying to make a basic todo app. I've updated my post to provide the render method to show where the deleteTodo is going. I've also updated my deleteTodo with an answer I got from this post. It kind of works, the only problem is it deletes all of the items in the todo list rather than just the single one.
class App extends Component {
state = {
inputValue: "",
todos: [{
value: "walk the dog",
done: false
},
{
value: "do the dishes",
done: false
}
]
}
addTodo = (e) => {
this.setState({
inputValue: e.target.value
});
}
handleSubmit = (e) => {
e.preventDefault();
// console.log('clicked')
const newTodo = {
value: this.state.inputValue,
done: false
}
const todos = this.state.todos;
todos.push(newTodo);
this.setState({
todos,
inputValue: ''
})
}
deleteTodo = (value) => {
// Take copy of current todos
const todos = [this.state.todos];
const filteredTodos = todos.filter((item) => item.value !== value);
this.setState({
todos: filteredTodos
})
}
render() {
return (
<div className="App">
<Form
addTodo={this.addTodo}
handleSubmit={this.handleSubmit}
/>
<List
todos={this.state.todos}
deleteTodo={this.deleteTodo}
/>
</div>
);
}
}
export default App;
You just need to filter that value from array and set new filtered array in the setState.
deleteTodo = (value) => {
// Take copy of current todos
const todos = [...this.state.todos];
const filteredTodos = todos.filter( (item) => item.value !== value);
this.setState({
todos: filteredTodos
})
}
Your use of filter appears to be the problem.. To create a new array of elements without the value using filter, you can try something like this:
EDIT: Updated answer with a full working demo
import React, {Component} from 'react';
import './App.css';
class Form extends Component {
constructor(props) {
super(props);
this.textRef = React.createRef();
}
render() {
return (
<form onSubmit={(e)=>{e.preventDefault(); this.props.handleSubmit(this.textRef.current.value)}}>
<input type="text" ref={this.textRef}/>
<input type="submit" value="add"/>
</form>
);
}
}
class List extends Component {
render() {
return (
<ul>
{
this.props.todos.map((todo) => (
<li key={todo.value}>
<p><input type="checkbox" checked={todo.done}/>{todo.value} </p>
<input type="button" onClick={() => (this.props.deleteTodo(todo.value))} value="delete"/>
</li>
))
}
</ul>
);
}
}
class App extends Component {
state = {
inputValue: "",
todos: [{
value: "walk the dog",
done: false
},
{
value: "do the dishes",
done: false
}
]
}
addTodo = (e) => {
this.setState({
inputValue: e.target.value
});
}
handleSubmit = (value) => {
const newTodo = {
value,
done: false
}
const todos = [...this.state.todos];
todos.push(newTodo);
this.setState({
todos,
inputValue: ''
})
}
deleteTodo = (value) => {
const todos = this.state.todos;
const filteredTodos = todos.filter((item) => item.value !== value);
this.setState({
todos: filteredTodos
})
}
render() {
return (
<div className="App">
<Form
addTodo={this.addTodo}
handleSubmit={this.handleSubmit}
/>
<List
todos={this.state.todos}
deleteTodo={this.deleteTodo}
/>
</div>
);
}
}
export default App;
Also, I changed your handleSubmit method to create a new Array to keep in line with React's functional paradigm
i have used lodash for such this.
lodash is a library for doing such thing https://lodash.com/
if you can get the same value object that you inserted while adding the rest is quite easy
you lodash to find the index in which you have the object in the array
on your delete function
const todos = this.state.todos;
const itemToRemove = {value: "walk the dog",done: false};
var index = _.findIndex(todos, itemToRemove);
const filteredTodos = todos.splice(index, 1)
this.setState({
todos: filteredTodos
})
Hope this will help

Categories