React toggle class - javascript

I want toggle class only click element. But now when i click anyone they are all active. And when i click a tag, i want add another class to card div. How should i update the code?
handleClick() {
const currentState = this.state.active;
this.setState({ active: !currentState });
}
<div className="container">
<div>
<h1>Components</h1>
<div>
<a href="#" onClick={this.handleClick.bind(this)} className= {this.state.active ? "card-icon active" : "card-icon"}>click</a>
<a href="#" onClick={this.handleClick.bind(this)} className= {this.state.active ? "list-icon active" : "list-icon"}>click</a>
</div>
</div>
<input type="text" placeholder="" className="input" onChange={(e)=>this.searchSpace(e)} />
<div className="card">
{items}
</div>
</div>

You are only tracking the state with one variable (active), but you need to keep track of each state separately. Try this:
Updated to handle toggle:
handleClick() {
const currentState = this.state.active;
this.setState({ active: !currentState });
}
<div className="container">
<div>
<h1>Components</h1>
<div>
<a href="#" onClick={this.handleClick.bind(this)} className= {this.state.active ? "card-icon active" : "card-icon"}>click</a>
<a href="#" onClick={this.handleClick.bind(this)} className= {!this.state.active ? "list-icon active" : "list-icon"}>click</a>
</div>
</div>
<input type="text" placeholder="" className="input" onChange={(e)=>this.searchSpace(e)} />
<div className={this.state.active ? "card" : "list"}>
{items}
</div>
</div>

You should be using multiple state variables and also use function to update the state, so when you set cart-icon to active the list-icon state does not change.
See the example below. let me know if it helps.
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
cartIconActive: false,
listIconActive: false,
};
this.handleCartIconClick = this.handleCartIconClick.bind(this);
this.handleListIconClick = this.handleListIconClick.bind(this);
}
handleCartIconClick() {
this.setState((prevState) => ({
...prevState,
cartIconActive: !prevState.cartIconActive,
}));
}
handleListIconClick() {
this.setState((prevState) => ({
...prevState,
listIconActive: !prevState.listIconActive,
}));
}
render() {
const { cartIconActive, listIconActive } = this.state;
return (
<div className="container">
<div>
<h1>Components</h1>
<div>
<a
href="#"
onClick={this.handleCartIconClick}
className={cartIconActive ? 'card-icon active' : 'card-icon'}
>
click
</a>
<a
href="#"
onClick={this.handleListIconClick}
className={listIconActive ? 'list-icon active' : 'list-icon'}
>
click
</a>
</div>
</div>
<input
type="text"
placeholder=""
className="input"
onChange={(e) => this.searchSpace(e)}
/>
<div className="card">{items}</div>
</div>
);
}
}

You can also do this with
function MyComponent (props) {
const [isActive, setActive] = useState(false);
const toggleClass = () => {
setActive(!isActive);
};
return (
<div
className={isActive ? 'your_className': null}
onClick={toggleClass}
>
<p>{props.text}</p>
</div>
);
}

Related

onClick of button triggering all the components to open - Reactjs

I implemented a Card component and basically generating a bunch of cards on some input data. I binded a setter function on button click on every card which basically expands and collapse it. Even after putting unique keys to the div is sort of triggering all the cards to open at once.
Here is the code piece:
import React, { useState } from 'react';
import PrettyPrintJson from './PrettyPrintJson';
import './Card.scss';
import '../App.scss';
const Card = (props) => {
const { data } = props;
const [collapse, toggleCollapse] = useState(true);
return (<div className="card-group">
{data.map((obj, idx)=>{
return <div className="card" key={`${idx}_${obj?.lastModifiedOn}`}>
<div className="card-header">
<h4 className="card-title">{`fId: ${obj?.fId}`}</h4>
<h6 className="card-title">{`name: ${obj?.name}`}</h6>
<h6 className="card-title">{`status: ${obj?.status}`}</h6>
<div className="heading-elements">
<button className="btn btn-primary" onClick={() => toggleCollapse(!collapse)}>Show Json</button>
</div>
</div>
<div className={`card-content ${!collapse ? 'collapse show' : 'collapsing'}`}>
<div className="card-body">
<div className="row">
<PrettyPrintJson data={ obj } />
</div>
</div>
</div>
</div>
})}
</div>
);
}
export default Card;
Create a component that manages it's own state and render that component.
const CardItem = ({ obj }) => {
const [collapse, toggleCollapse] = useState(true);
return (<div className="card">
<div className="card-header">
<h4 className="card-title">{`fId: ${obj?.fId}`}</h4>
<h6 className="card-title">{`name: ${obj?.name}`}</h6>
<h6 className="card-title">{`status: ${obj?.status}`}</h6>
<div className="heading-elements">
<button className="btn btn-primary" onClick={() => toggleCollapse(!collapse)}>Show Json</button>
</div>
</div>
<div className={`card-content ${!collapse ? 'collapse show' : 'collapsing'}`}>
<div className="card-body">
<div className="row">
<PrettyPrintJson data={ obj } />
</div>
</div>
</div>
</div>)
}
then render it like
{data.map((obj, idx)=> (<CardItem obj={obj} key={idx} />))}
I think you can declare a state which is a type of int. After then, you can use the if-statement of index(idx) and state.
Like this:
const [collapsedCardNumbers, toggleCollapseCard] = useState([]);
const addCardNumber = (idx, prevState) => {
const arr_cardNum = prevState
!arr_cardNum .includes(idx) && arr_cardNum .push(idx)
return arr_cardNum
}
...
{data.map((obj, idx)=>{
return <div className="card" key={`${idx}_${obj?.lastModifiedOn}`}>
<div className="card-header">
<h4 className="card-title">{`fId: ${obj?.fId}`}</h4>
<h6 className="card-title">{`name: ${obj?.name}`}</h6>
<h6 className="card-title">{`status: ${obj?.status}`}</h6>
<div className="heading-elements">
<button className="btn btn-primary" onClick={() => toggleCollapseCard(prevState => addCardNumber(idx, prevState))}>Show Json</button>
</div>
</div>
<div className={`card-content ${collapsedCardNumbers.includes(idx) ? 'collapse show' : 'collapsing'}`}>
<div className="card-body">
<div className="row">
<PrettyPrintJson data={ obj } />
</div>
</div>
</div>
</div>
})}

React How to show individual data into popup

I am learning react I want to show movie data when clicking on particular div. currently, I called fancy box which is not right method to get the result
So I need help to show movie data once click on particular div.
class App extends React.Component {
constructor() {
super();
this.state = {
data: [],
search: '',
};
}
updateSearch(event) {
this.setState({search: event.target.value.substr(0, 20)});
}
componentDidMount() {
fetch('http://www.omdbapi.com/?apikey=MyKey&s=fast&plot=full')
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse);
this.setState({
data: findresponse.Search,
});
});
}
render() {
let filteredMovie = this.state.data.filter((dynamicData) => {
return dynamicData.Title.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1;
});
return (
<div className="container movies_list">
<div className="row">
<div className="col-md-12 p-4">
<form>
<input
type="text"
className="form-control"
placeholder="Search"
value={this.state.search}
onChange={this.updateSearch.bind(this)}
/>
</form>
</div>
{filteredMovie &&
filteredMovie.map((dynamicData, key) => (
<div className="col-md-3 mb-3" key={key}>
<div className="card">
<img src={dynamicData.Poster} className="card-img-top" alt="..." />
<div className="card-body">
<h6 className="card-title">{dynamicData.Title} </h6>
<h6 className="card-title">Year: {dynamicData.Year} </h6>
<p className="card-text">{dynamicData.Plot} </p>
<a
data-fancybox
data-src="#hidden-content"
href="javascript:;"
className="btn btn-info"
>
View
</a>
<div id="hidden-content">
<img src={dynamicData.Poster} className="card-img-top" alt="..." />
<h2>{dynamicData.Title}</h2>
<p>{dynamicData.Year}</p>
</div>
</div>
</div>
</div>
))}
</div>
</div>
);
}
}
I highly recommend Reakit for modal & popovers.

Tranfser props to sibling component

Instead of% username%, I would like the current name and name to be displayed in the modal title
user's surname. I can't make this task. I
after solving the problem, give ideas how I can optimize my code.
Code:
class App extends React.Component {
state= {
show: false,
};
showModal = () =>{
this.setState({
show: !this.state.show
});
};
render() {
const users = this.props.data.users;
const userList = users.map(user => <User key={user.id} user={user} onOpen={this.showModal} name={user.name} surname={user.surname}/>)
return (
<div className="container">
{userList}
{this.state.show ? < Modal onClose={this.showModal} show={this.state.show}/> : null}
</div>
)
}
}
class User extends React.Component{
onOpen = () => {
this.props.onOpen && this.props.onOpen();
};
render(){
const {avatar, name, surname, city, country} = this.props.user;
return(
<div className="box">
<img src={avatar} alt="" className="avatar" />
<h3 className="box-title">{`${name} ${surname}`}</h3>
<p className="box-description">{`${city}, ${country}`}</p>
<div className="button-wrap">
<a href="#" className="button" onClick={()=> this.onOpen()} >Report user</a>
</div>
</div>
)
}
}
class Modal extends React.Component {
onClose = () => {
this.props.onClose && this.props.onClose();
};
render() {
if(!this.props.show){
return null;
}
// tak wygląda struktura HTML dla modal boxa
return (
<div className="modal">
<div className="modal-background"></div>
<div className="modal-content">
<div className="box">
<h3 className="modal-title">Report user</h3>
<textarea rows="6"></textarea>
<div className="button-wrap">
<a href="#" className="button button-link" onClick={() => {
this.onClose()}}>Cancel</a>
<a href="#" className="button ml-auto" onClick={()=> alert("ok")}>Report</a>
</div>
</div>
</div>
</div>
)
}
}
ReactDOM.render(<App data={data} />, document.querySelector("#app"))
using state ReportUsr to store the user you want to report changed by function this.ReportUsr in App class then pass function as prop Report to User class to call it OnClick with the value surname for that instance of User component
then Modal component created from App class has CONTENT which is the App.state.ReportUsr
< Modal onClose={this.showModal} show={this.state.show} >{this.state.ReportUsr}</ Modal>
LiveExample
https://h4i1e.csb.app/
Code https://codesandbox.io/s/modern-browser-h4i1e

How to filter data using react?

I have created search filter but I am not able to type anything in search input why so ? I have created searchTermChanged method but why is it not working ? When user types in input field the projects should get filtered based on title.
Code:
import Projects from '../../data/projects';
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
search: '',
projects: Projects
}
}
searchTermChanged = (event) => {
this.setState({ projects: this.state.projects.filter(val =>
val.title.toLowerCase().indexOf(this.state.search.toLowerCase()) > -1 )
})
}
render() {
return (
<div>
<div className="header">
<div className="md-form mt-0 customsearch">
<input className="form-control" type="text" placeholder="Search projects" aria-label="Search"
value={this.state.search}
onChange={e => this.searchTermChanged(e.target.value)}
/>
</div>
</div>
<div class="container-fluid">
<div class="row">
{this.state.projects.map((val,index) => (
<div class="col-3">
<Card title={val.title} by={val.by} blurb={val.blurb}
url={val.url} funded={val.funded} backers={val.backers} imgurl={index}/>
</div>
))}
</div>
</div>
</div>
)
}
}
You need to make sure you're making correct use of the state.
import Projects from '../../data/projects';
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
search: '',
projects: Projects
}
}
searchTermChanged = (search) => {
this.setState({
//Update the search state here.
search,
//Use the current search state to filter
projects: this.state.projects.filter(val =>
val.title.toLowerCase().indexOf(search.toLowerCase()) > -1 )
}
);
}
render() {
return (
<div>
<div className="header">
<div className="md-form mt-0 customsearch">
<input className="form-control" type="text" placeholder="Search projects" aria-label="Search"
value={this.state.search}
onChange={e => this.searchTermChanged(e.target.value)}
/>
</div>
</div>
<div class="container-fluid">
<div class="row">
{this.state.projects.map((val,index) => (
<div class="col-3">
<Card title={val.title} by={val.by} blurb={val.blurb}
url={val.url} funded={val.funded} backers={val.backers} imgurl={index}/>
</div>
))}
</div>
</div>
</div>
)
}
}
I think if you don't need to change the projects you can also do the bellow to simplify your logic:
constructor(props) {
super(props);
this.state = {
search: ''
}
}
render() {
let {search} from this.state;
let myProjects = projects.filter((p) => {
p.title.toLowerCase().indexOf(search.toLowerCase) > -1
});
return (
<div>
<div className="header">
<div className="md-form mt-0 customsearch">
<input className="form-control" type="text" placeholder="Search projects" aria-label="Search"
value={this.state.search}
onChange={e => this.setState({search: e.target.value})}
/>
</div>
</div>
<div class="container-fluid">
<div class="row">
{myProjects.map((val,index) => (
<div class="col-3">
<Card title={val.title} by={val.by} blurb={val.blurb}
url={val.url} funded={val.funded} backers={val.backers} imgurl={index}/>
</div>
))}
</div>
</div>
</div>
)
}
You need to user Projects variable directly to filter otherwise filter changes will search on existing state. You need to set search value to refect what is your input
searchTermChanged = (event) => {
console.log(event);
this.setState({
projects: Projects.filter(val =>
val.title.toLowerCase().indexOf(event.toLowerCase()) > -1 ),
search: event <-- here
})
}
stackblitz: https://stackblitz.com/edit/react-fyf7fr
You are not changing the state of "search".
Assuming u have an input like this:
<input type="text" id="whatever" className="whatever" onChange={(event) => props.searchTermChanged(e.target.value)} />
you can change your method searchTermChanged
searchTermChanged = (value) => {
this.setState({search: value});
this.setState({ projects: this.state.projects.filter(val =>
val.title.toLowerCase().indexOf(value.toLowerCase()) > -1 )
});
}
The reason why u use "value" instead of "this.state.search" here "indexOf(value.toLowerCase())" its because setState is asynchronous and you can reach that piece of code with state outdated. And you are sure that "value" has the right value.

How to pass dynamic value to div element and then access it - React ?

I'm mapping all of my files
_renderItems = files =>
files
? files.map((item, i) => {
return <ProjectItemUser {...item} key={i} index={i} />;
})
: null;
and then I'm trying to display it ProjectItemUser
class ProjectItemUser extends Component {
render() {
return (
<div>
<div className="book_item">
<div className="book_header">
<h2>{this.props.name}</h2>
</div>
<div className="book_this">
<div className="book_author">{this.props.subject}</div>
<div className="book_bubble">
<strong>Study: </strong> {this.props.study}
</div>
<div className="book_bubble">
<strong>Grade: </strong> {this.props.grade}
</div>
<FontAwesomeIcon icon="trash" id="trash" />
</div>
</div>
</div>
);
}
}
This basically displays all the files, and each file is its own separate row. I would like to assign value to div element on each iteration, so I can control which file has been clicked.
I can access my id with: this.props._id
Should this be done using refs and if so, how ?
You should pass onClick function as parameter
_renderItems = files =>
files
? files.map((item, i) => {
return <ProjectItemUser {...item} key={i} index={i} onClick={() => { console.warn(item) } />;
})
: null;
class ProjectItemUser extends Component {
render() {
return (
<div>
<div className="book_item">
<div className="book_header">
<h2>{this.props.name}</h2>
</div>
<div className="book_this">
<div className="book_author">{this.props.subject}</div>
<div className="book_bubble">
<strong>Study: </strong> {this.props.study}
</div>
<div className="book_bubble">
<strong>Grade: </strong> {this.props.grade}
</div>
<FontAwesomeIcon icon="trash" id="trash" />
<Button onClick={this.props.onClick} label="Click on me" />
</div>
</div>
</div>
);
}
}

Categories