React - How to filter a button - reactjs

I'm working through some React tutorials and trying to figure out how to filter buttons out of a button group by searching for a term. My filter function works for text but I can't figure out how to get it to work with buttons.
<div className="searchbar">
<form>
<input type="text" placeholder="Search..." onChange={this.searchHandler} />
</form>
{
this.state.drinks.filter(searchingFor(this.state.term)).map(drink =>
<div key={ drink.id } >
{ drink.title }
</div>)
}
</div>
I am able to filter text with this (drink.title) but I want to filter the buttons in the section below. Is this possible with what I currently have? Sorry if this is a vague question, I'm brand new to React and would appreciate any help.
<Grid.Column className="left-col" width="3">
<Container >
<Menu >
{drinks && drinks.length
? <Button.Group vertical widths={drinks.length} >
{Object.keys(drinks).map((key) => {
return <Button size="large" fluid active={drink && drink.id === drinks[key].id} key={key} onClick={()=>this.getDrink(drinks[key].id)}>
{drinks[key].title}
</Button>
})}
</Button.Group>
: <Container textAlign='center'>No drinks found.
</Container>
}
</Menu>
</Container>
</Grid.Column>
and the search function
function searchingFor(term) {
return function(x) {
return x.title.toLowerCase().includes(term.toLowerCase()) || !term
}
}

Related

How can I add item on localStroge through ReactJS

I don't understand how I can add an item on localStroge with the handle change method in react js.
The problem is I want to add a favorite list. When I click the favorite list all checkbox fill I need to control them.
I want to store the filled item in my local storage. handlechange function fill all favorite icon why?
Every click will be a single item fill. Is it possible to Material UI or Martial UI checkBox icon? How can I handle it?
Here is my UI view
function Main() {
// Here is my state define
const [checked, setChecked] = React.useState(
localStorage.getItem("love") === "true"
);
const handleChange = (e) => {
localStorage.setItem("love", `${e.target.checked}`);
setChecked(e.target.checked);
console.log(e.target.checked);
};
return (
<>
<div className="row mt-5">
{isLoading ? (
<>
{Array.from({ length }).map((_, i) => (
<MainLoading key={i} />
))}
</>
) : error ? (
<p>Error occured</p>
) : (
<>
{data?.map((product) => (
<div className="col-md-3 mb-5 text-center" key={product.id}>
<img
className="w-100"
style={{ height: "200px", objectFit: "contain" }}
src={product.image}
alt=""
/>
<div>{product.title.substring(0, 20)}</div>
<button
onClick={() => handelAddTocard(product)}
className="mt-3"
>
Add to card
</button>
<button>
<Link
to={`/details/${product.id}`}
className="mt-3 text-decoration-none text-black"
>
view details
</Link>
</button>
{/* How can i control evey single item */}
<Checkbox
checked={checked}
onChange={handleChange}
icon={<FavoriteBorder />}
checkedIcon={<Favorite />}
/>
</div>
))}
</>
)}
</div>
</>
);
}
export default Main;
The problem is that you are using a boolean and you have no way to identify a specific item.
If you want to favorite multiple items, I would use something like this:
const [checked, setChecked] = React.useState(
JSON.parse(localStorage.getItem("loveIds") || "[]")
);
const handleCheck = (id, productChecked) => {
const newItems = productChecked ? [...checked, id] : checked.filter(x => x !== id);
localStorage.setItem("loveIds", JSON.stringify(newItemS));
setChecked(newItems);
console.log(newItems);
};
// ...
<Checkbox
checked={checked}
onChange={(e) => handleCheck(product.id, e.target.checked)}
icon={<FavoriteBorder />}
checkedIcon={<Favorite />}
/>

How to create a component like Bootstrap accordion?

I want a component to behave exactly like Accordion.
I have managed to do that.
But I am facing one issue.
If one question is open and a user tries to open the other question,it closes the first question.
I do not want that.
I want both of them to remain open and it should be closed if a user clicks on the question again.
Here is the code -->
class Accordion extends React.Component {
constructor() {
super();
this.state = {
answer: false,
selectedQue: null,
};
}
toggleAnswer = (index) => {
const { answer } = this.state;
this.setState({
selectedQue: index,
answer: !answer,
});
};
render() {
const { answer, selectedQue } = this.state;
return (
<Row className="m-t-10">
<Col md={12} sm={12} xs={12}>
{map(
questionAnswer,
(item, index) =>
item && (
<div key={index} onClick={() => this.toggleAnswer(index)}>
<div className="d-flex justify-content-between">
<Label
header={item.key}
color={index === selectedQue && answer ? '#406AE8' : '#415070'}
/>
<span className="float-right">
<Icons
className={cx(
'vertical-align-middle',
index === selectedQue && answer
? 'ac-icon-arrow-up-xs'
: 'ac-icon-arrow-down-xs',
)}
/>
</span>
</div>
{index === selectedQue && answer && (
<div>
<span
dangerouslySetInnerHTML={{
__html: item.value,
}}
/>
</div>
)}
<hr />
</div>
),
)}
</Col>
</Row>
)
}
}

How can show the input field on toggle?

I want to show the input field on toggling. The toggling is working but it is not showing the input field. How can I achieve this? I've tried but that is not showing the input field.
Here's the code:
handleToggle=()=>{
console.log('In handletoggle')
this.setState({
milestone_based_payment:!this.state.milestone_based_payment
})
}
percentRate=()=>{
<>
<div className="percent-rate-container">
<Grid container>
<Grid item md={12} lg={12} xs={12}>
<div className="percent-rate">PERCENT RATE</div>
<div>
<InputBase
className={`milestone-percent-rate`}
autoComplete={"off"}
placeholder={"PERCENT RATE"}
maxLength="100"
value={this.state.percent_rate}
onChange={(e)=>{this.handleChange(e, "percent_rate")}}
/>
{
this.state.percent_rate_error && (
<div className="input-error-style">{this.state.percent_rate_error}</div>
)
}
</div>
</Grid>
</Grid>
</div>
</>
}
togglePayment=()=>{
const {milestone_based_payment} = this.state;
console.log('togglepayment')
return(
<div>
<img src={milestone_based_payment ? PRIVATE_SwITCH : PUBLIC_SwITCH} alt="private-public"
onClick={()=>this.handleToggle()}
style={{cursor: "pointer"}}/>
</div>
);
}
You can show/hide input field on true / false condition like this:
showHideInput() {
if(this.state.milestone_based_payment === true) {
return <input />
}
}
// and call the method in other method
// or inline condition
(this.state.milestone_based_payment === true) ? <input /> : <React.Fragment />

Tabs Component including Cards crashing

I have to build a web application using React & Material-UI frameworks.
I use a tab component to display mutliple cards (includiing charts) inside. The first tab works pretty good, but when I want to switch to the second tab, there is no displaying inside the tab. Worst, I can't return to the first tab ; the Tabs Component is completely dead.
You can find my code here :
class NavTabs extends React.Component {
state = {
value: 0,
};
handleChange = (value) => {
this.setState({ value });
};
render() {
const { classes } = this.props;
const { value } = this.state;
return (
<div className={classes.root}>
<AppBar position="static">
<Tabs fullWidth value={value} onChange={this.handleChange}>
<Tab label="FINANCIAL" />
<Tab label="OPERATIONAL" />
<Tab label="PLANNING" />
</Tabs>
</AppBar>
{value === 0 && <TabContainer>
<div className={classes.card_up}>
<CashWindow />
<SalesWindow />
</div>
<div className={classes.card_up}>
<CostsWindow />
<MarginsWindow />
<ContingenciesWindow />
</div>
<Button className={classes.button_more}>Details</Button>
</TabContainer>}
{value === 1 && <TabContainer>
<div className={classes.card_up}>
<OpportunitiesWindow />
<CriticalIssuesWindow />
</div>
<div className={classes.card_up}>
<QualityWindow />
</div>
<Button className={classes.button_more}>Details</Button>
</TabContainer>}
{value === 2 && <TabContainer>
<div className={classes.card_up}>
<ResourcesWindow />
</div>
</TabContainer>}
</div>
);
}
}
I don't have any error with the others components, because when I am trying to move components of the second tab into the first, it works. My conclusion is that the problem come from the Tabs Component.
Does anyone know how to fix this ?
Maybe I am doing wrong, I am a beginner in React programming.

React having onClick work only once on a component

Hello I am trying to build a forum site. I have simple categories and comments. I have a button that displays a text box to enter a comment on a category, but when I click the button it opens text boxes on every category. I just want one text box. Here is the code I have so far. Any help would be appreciated. Thanks
state = { showing: true };
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
<button
className="label"
onClick={() => this.setState({ showing: !showing })}
>
Add Comment
</button>
{showing ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
<main className="categories">
{this.renderLists(this.state.category)}
</main>
</div>
);
}
Since you are controlling render of the form with a single state value, ever form for every item renders the form when the state value changes.
You should set a unique value on state to show single form every time.
Saving currently active items id to state and checking if that item is active or not can be a simple solution. This also ensures to only single form to be active. If you need to enable multiple forms to be active, you can change below code to hold an array of ids and checking if the id exist in array or not. This implementation also requires you to remove the id from array on a second click to remove form for that item.
Sample
state = { showing: ''};
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
<button
className="label"
{/* Save item's id to state */}
onClick={() => this.setState({ showing: category._id })}
>
Add Comment
</button>
{/* check item's id */}
{(showing === category._id) ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
You can set the dynamic state for each of your category. I have made it below. Initially it was not there in state. On clicking the button, it will update the state with new key(such as categoryName) as true. I have fixed it as toggle. If the required key is true then it will become false.
item.state = { showing: true };
renderLists(categories) {
const { showing } = this.state;
if (categories == null) return <div />;
return (
<ul className="ul">
{categories.map(category => {
let categoryName = category.name // get the categoryName in variable
return (
<li id={category._id} className="categories" key={category._id}>
{category.name}
<Posts categ={category._id} />
//You can also access the object values by using bracket ([]) notation. You can set the dynamic state with unique key, may be we use name as key here
<button
className="label"
onClick={() => {(this.state[categoryName] != undefined) ? (this.state[categoryName] ? this.setState({ [categoryName]: false }) : this.setState({ [categoryName]: true })) : this.setState({ [categoryName]: true })} }
>
Add Comment
</button>
{this.state[categoryName] ? (
<div>
<form method="post" action="/post/create-posts">
<input type="text" name="body" />
<input type="hidden" name="cat" value={category._id} />
<input type="submit" value="Submit" />
</form>
</div>
) : null}
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
<main className="categories">
{this.renderLists(this.state.category)}
</main>
</div>
);
}

Resources