I'm having problem with sliding menu in just one item.
When I click on the config button every item shows menu. I tried to figure out something by passing props {mail.id} but I'm afraid I don't understand this.
I would like to have sliding menu just in one item -- the clicked one.
This is ConfigButton
import React, { Component } from "react";
import './Menu.css';
class ConfigButton extends Component {
render() {
return (
<button className="configButton"
onClick={this.props.onClick}
>
<i className="configButtonIcon fas fa-cog"></i>
</button>
);
}
}
export default ConfigButton;
And this is the Component which renders:
import React, { Component } from 'react';
import { NavLink, HashRouter } from 'react-router-dom';
import axios from 'axios';
import Menu from './Menu';
import ConfigButton from './ConfigButton';
const API = myAPI;
const navLinkStyle = {
textDecoration: 'none',
color: '#123e57'
};
class Emails extends Component {
constructor(props) {
super(props);
this.state = {
visible: false,
mails: []
};
this.handleMouseDown = this.handleMouseDown.bind(this);
this.toggleMenu = this.toggleMenu.bind(this);
}
handleMouseDown(e) {
this.toggleMenu();
e.stopPropagation();
}
toggleMenu() {
this.setState({
visible: !this.state.visible
});
}
componentDidMount() {
axios.get(API)
.then(response => {
const mails = response.data;
this.setState({ mails });
})
}
truncate = (text, chars = 140) =>
text.length < chars ? text : (text.slice(0, chars) + '...')
render() {
let mails = this.state.mails;
console.log(mails);
mails = mails.map(mail => {
return (
<div key={mail.id}>
<div className='mail'>
{
!mails.displayed
? <i className="notDisplayed fas fa-circle"></i>
: <i className="displayed far fa-circle"></i>
}
<HashRouter>
<NavLink
to={`/openemail/${mail.id}`}
style={navLinkStyle}
>
<ul className='ulMailWrap'>
<div className='mailHeader'>
<li>{mail.sender}</li>
<li>{mail.created}</li>
</div>
<li>{mail.subject}</li>
<li>{this.truncate(mail.message)}</li>
</ul>
</NavLink>
</HashRouter>
<ConfigButton onClick={this.handleMouseDown} />
<Menu handleMouseDown={this.handleMouseDown}
menuVisibility={this.state.visible}
/>
</div>
</div>
)
});
return (
<div>
{ mails }
</div>
);
}
}
export default Emails;
You can pass a function that will send a different parameter to the handler, depending on value of each element in the array.
Do something like this:
...
<div key={mail.id} onClick={() => this.handleOpenMenu(mail.id)}>
...
Then at the handler:
handleOpenMenu = id => {
// do different stuffs on the id you get here
this.setState({ visibleMenuId: id });
}
And then change the props you are passing to your menu component:
<Menu menuVisibility={this.state.visibleMenuId === mail.id} />
Related
I am new to React. I am trying to display new component in the content on click of menu from Navbar. But the return of component on click function doesnot work. So return doesnot work. Here are my files. Click function "getItemsData" works but the component is not returned. I am trying to create a application with restaurant menu and it relevant content
App.jsx
import React from 'react';
import "./style.css";
import Slider from "./carousel.js"
class App extends React.Component{
render(){
return(
<div>
<Header/>
</div>
);
}
}
class Header extends React.Component{
constructor(props){
super(props);
this.state = {
sections: [],
menu: []
};
}
componentDidMount(){
fetch('http://localhost:3001/api/sections')
.then(res => res.json())
.then(sections => this.setState({ 'sections': sections }))
fetch('http://localhost:3001/api/menu')
.then(res => res.json())
.then(menu => this.setState({ 'menu': menu }))
}
render(){
return(
<div id="header-bar">
<div id="header-logo">
<img src={require('./images/1200px-Burger_King_Logo.png')} alt="Logo" id="logo-class"></img>
</div>
<Slider sections={this.state.sections} menu={this.state.menu} />
</div>
);
}
}
export default App;
carousel.js
import React , { Component } from 'react';
import contentCards from "./contentcards.js";
const Slider = (data) => {
console.log(data)
var Menuoptions = data.menu.options
var Sectionsref = data.sections
const getItemsData = (sectionData) => {
sessionStorage.setItem("sectionData" , JSON.stringify(sectionData));
return <contentCards />;
}
return(
<div className="sectionNavBar">
{(()=> {
if (Menuoptions !== undefined && Sectionsref !== undefined) {
if (Menuoptions.length > 0 && Sectionsref.length > 0){
let rowmenu = []
for(let i=0; i< Menuoptions.length ; i++){
for(let j=0; j<Sectionsref.length; j++){
if(Menuoptions[i]._ref === Sectionsref[j]._id){
// console.log(Menuoptions[i]._ref+ "==" +Sectionsref[j]._id)
let imageId = Sectionsref[j].carouselImage.asset._ref;
imageId = imageId.slice(6)
imageId = imageId.replace("-png", ".png")
//console.log(Sectionsref[j])
rowmenu.push(<div key={j} className="listNavBar" onClick = {() => getItemsData(Sectionsref[j])}> <img src={window.location.origin + '/images/'+imageId} className= "navBar-image" /> <br/>{Sectionsref[j].name.en} </div>)
}
}
}
return rowmenu
}
}
})()}
</div>
)
}
}export default Slider
contentCards.js
import React , { Component } from 'react';
class contentCards extends React.Component{
render(){
return (
<div className = "cardColumn"> Menu1 </div>
)
}
}
export default contentCards
Custom components names must be uppercased or React will treat them as DOM elements.
React treats components starting with lowercase letters as DOM tags.
// not <contentCards />
<ContentCards />
I am trying to save the value of the button as a string.If i click residence button it will save the value in categoryName as 'residence' or 'commercial' and redirect to another page .I have built a Rest API in the backend to bind and save the value in database.The code is something like this
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
class CustomizedButtons extends React.Component {
constructor(props) {
super(props);
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
category: " ",
};
}
saveValue = () => {
console.log('savecategory');
axios.post( this.state.apiUrl+'/api/v1/leadsurvey/category', {
'categoryName':this.state.category,
}, {})
};
render() {
const { classes} = this.props;
return (
<div>
<div>
<p>What is the type of your property?</p>
<div>
<button onClick={() => this.saveValue()}>Residence</button>
<button onClick={() => this.saveValue()}>Commercial</button>
</div>
<div style={{marginTop: '90px'}}>
</div>
</div>
</div>
);
}
}
export default CustomizedButtons;
I am not getting how to make it work to bind and save.In case of saving form value i did something like this.
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
FreeQuoteName :"",
};
this.handleFreeQuoteName = this.handleFreeQuoteName.bind(this);
saveFreeQuote = () => {
console.log('saveFreeQuote ...', this.state);
axios.post( this.state.apiUrl+'/api/v1/SalesLead/save', {
'name': this.state.FreeQuoteName,
}
}
handleFreeQuoteName(event) { this.setState({ FreeQuoteName: event.target.value }); }
<Form>
<p>Name*</p>
<input maxLength="30" onChange={this.handleFreeQuoteName} value={this.state.FreeQuoteName}
type="text" placeholder="Enter name here"/>
<div style={{textAlign:'center', marginTop:'35px', marginBottom:'22px'}} className={card.disable}>
<button disabled={isDisabled} type="button" fullwidth="true" variant="contained"
onClick={() => this.saveFreeQuote()} style={{padding: '9px 0px'}}>Submit</button>
</Form>
I want to do same for the value button.If i click the button it will save the value as a string and redirect to another page.How can i do it?
from your post I assumed that you want to save button value in state and also want to initiate the axios request while button click.
try to change like below
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import axios from 'axios';
class CustomizedButtons extends React.Component {
constructor(props) {
super(props);
this.state = {
apiUrl:config.publicRuntimeConfig.publicRuntimeConfigValue.apiUrl,
category: "",
};
}
saveValue = (e) => {
console.log('savecategory', e.target.innerHTML);
this.setState({
category: e.target.innerHTML
}, this.makeAxiosRequest);
};
makeAxiosRequest = () => {
axios.post( this.state.apiUrl+'/api/v1/leadsurvey/category', {
'categoryName':this.state.category,
}, {})
};
render() {
const { classes} = this.props;
return (
<div>
<div>
<p>What is the type of your property?</p>
<div>
<button onClick={this.saveValue}>Residence</button>
<button onClick={this.saveValue}>Commercial</button>
</div>
<div style={{marginTop: '90px'}}>
</div>
</div>
</div>
);
}
}
export default CustomizedButtons;
here am using callback function inside setState() to initiate axios request after button value saved in state.
Hope this helps.
When a user like a post, then the count is incremented in ui. Bu when a user remove the like then count ui is not changing though it is changed in server.How to solve it?
When a user like a post, then the count is incremented in ui. Bu when a user remove the like then count ui is not changing though it is changed in server.How to solve it?
import React from 'react';
import moment from 'moment';
import CommentForm from './CommentForm';
import CommentList from './CommentList';
import CommentModal from './CommentModal';
import { connect } from 'react-redux';
import { startAddComment, startAddLike, startRemoveLike } from
'../actions/post';
import { Link } from 'react-router-dom';
import UserInfo from './UserInfo';
class PostListItem extends React.Component{
constructor(props){
super(props);
this.state = {
isliked: false,
commentM: undefined,
likes: this.props.likes
}
}
componentDidMount(){
if(this.props.likes.includes(this.props.user.uid)){
this.setState(() => ({isliked:true}));
}
}
onClickedLike = () =>{
if(this.state.isliked === false){
this.props.dispatch(startAddLike(this.props._id));
this.setState(()=>{
console.log(this.props);
return{
isliked:true
}
});
} else{
this.props.dispatch(startRemoveLike(this.props._id));
this.setState(()=>({isliked:false}));
}
}
openModal = () =>{
this.setState({commentM: this.props.comments});
}
closeModal = () =>{
this.setState(({commentM: undefined}));
}
render(){
return(
<div className="post">
<div className="post__header">
<UserInfo user={this.props.author}
time={this.props.createdAt}/>
{
(this.props.user.uid === this.props.author.uid)?
<Link to={`/edit/${this.props._id}`}
className="post__edit">
Edit</Link>:''
}
{/* <p className="post__time">
{moment(this.props.createdAt).fromNow()}</p> */}
</div>
<div className="post__caption">{this.props.caption}</div>
<img src={this.props.content} className="post__content"/>
<div className="post__extra">
<div className="post__lc">
<button className="post__button"
onClick={this.onClickedLike}
>{this.state.isliked? <i className="fas fa-futbol"></i>
: <i className="far fa-futbol"></i>}
</button>
<button className="post__button"
onClick={this.openModal}><i className="far fa-
comment"></i>
</button>
</div>
{this.props.likes.length !== 0 && <p className="post__like">
{this.props.likes.length} {this.props.likes.length === 1? 'like':'likes'}
</p>} // likes count is not changing while removing the like(ui only)
<CommentModal
commentM={this.state.commentM}
closeModal={this.closeModal}/>
<CommentForm onSubmit={(comment) => {
this.props.dispatch(startAddComment(this.props._id,
comment));
}} />
{this.props.comments && <CommentList comments=
{this.props.comments}/>}
</div>
</div>
);
}
};
const mapStateToProps = (state) => {
return{
user: state.auth
}
}
export default connect(mapStateToProps)(PostListItem);
my setState doesn't chance the state in the handleClick event handler.
I'm sure the handleClick works because it logs the param.
I'm kind of new to React so I must be overlooking something.
Does this mean there is something wrong with my handleClick function?
Any advice would be really appreciated!
import React from 'react';
import './Projects.css';
import Footer from '../../Components/Footer/Footer.js';
import ProjectPage from
'../../Components/ProjectPage/ProjectPage.js';
import { Redirect, Link } from 'react-router-dom';
class Projects extends React.Component {
constructor(props) {
super(props);
this.state= {
title: "kaufmann house",
content: "charles",
}
this.getImages = this.getImages.bind(this);
}
getImages() {
var VisibilitySensor = require('react-visibility-sensor');
return this.props.projectList.map((post,index) =>
<div>
<div className="projects">
<VisibilitySensor onChange={isVisible =>
this._onChange(isVisible, post.title)}>
<img key={post.id} src={post.featureImage}
className='projectImage' alt='projectImage' onClick= .
{this.handleClick.bind(this, post.content)}/>
</VisibilitySensor>
</div>
</div>
)
}
_onChange = (isVisible, param) => {
isVisible && this.setState({title: param});
};
handleClick = (param) => {
console.log(param);
this.setState({content: param});
};
render() {
return (
<div>
<Link to={{pathname: `/ProjectPage/${this.state.title}`,
state: {
info: `${this.state.content}`}
}}>{this.getImages()}</Link>
<Link to={{pathname: `/ProjectPage/${this.state.title}`,
state: {
info: `${this.state.content}`}
}}>
<Footer title={this.state.title}/>
</Link>
</div>
)
}
}
export default Projects;
this.state= {
title: "kaufmann house",
content: "charles",
}
Your state contains title and content. You have to setState like below. Otherwise, your new state will not update correctly because you replaced the whole state object.
_onChange = (isVisible, param) => {
isVisible && this.setState({
...this.state,
title: param
});
};
handleClick = (param) => {
console.log(param);
this.setState({
...this.state,
content: param
});
};
I would suggest the following changes:
1) Move var VisibilitySensor = require('react-visibility-sensor');
to the top of your file to keep your component clean
import React from 'react';
import './Projects.css';
import Footer from '../../Components/Footer/Footer.js';
import ProjectPage from
'../../Components/ProjectPage/ProjectPage.js';
import { Redirect, Link } from 'react-router-dom';
import VisibilitySensor from 'react-visibility-sensor';
2) Regarding your click handler, it is a bad practice to create handler functions using bind, because this may cause a performance issue since a new function will be created on each render. you can use an arrow function and set data-[attribute]
to add data to your component
getImages() {
//var VisibilitySensor = require('react-visibility-sensor'); remove this line
return this.props.projectList.map((post,index) => (
<div key={post.id}>
<div className="projects">
<VisibilitySensor onChange={isVisible =>
this._onChange(isVisible, post.title)}>
<img src={post.featureImage}
data-content={post.content}
className='projectImage'
alt='projectImage'
onClick={this.handleClick}/>
</VisibilitySensor>
</div>
</div>
))
}
handleClick = (e) => {
var content = e.target.dataset.content;
this.setState((state) => ({
...state,
content
}))
}
I need to render a modal/lightbox component dynamic into a list array component, but it only renders the last modal content.
How can I turn this modal component dynamic to call it from the main component and populate it with correct data from an object array?
My List component is:
import React, { Component } from 'react';
import LightBox from './LightBox';
class ListPrice extends Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
}
toggleModal = () => {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return (
<div>
{this.props.products.map(product => {
return(
<div>
<a key={product.id} onClick={this.toggleModal}>
<h3>{product.title}</h3>
<p>{product.description}</p>
</a>
<LightBox key={product.id} show={this.state.isOpen}
onClose={this.toggleModal}>
{product.modalContent}
</LightBox>
</div>
);
})}
</div>
);
}
}
export default ListPrice;
And my LightBox component is (I removed styles to display short code here):
import React from 'react';
import PropTypes from 'prop-types';
class LightBox extends React.Component {
render() {
if(!this.props.show) {
return null;
}
return (
<div>
<div>
{this.props.children}
<div>
<button onClick={this.props.onClose}>
Close
</button>
</div>
</div>
</div>
);
}
}
LightBox.propTypes = {
onClose: PropTypes.func.isRequired,
show: PropTypes.bool,
children: PropTypes.node
};
export default LightBox;
Thank you for any advice :)
With show={this.state.isOpen} you always display all the modals - only the last one is visible as other modals are displayed behind it.
In order to fix that you must show only the selected dialog. You can store opened dialog in state with construct like this.setState({ openedDialog: product.id }).
Then you can query if the dialog is open by using this.state.openedDialog === product.id. That should do the job.
openModal = (id) = () => {
this.setState({
openedDialog: id
});
}
closeModal = () => {
this.setState({
openedDialog: null
});
}
show={this.state.openedDialog === product.id}
onClick={this.openModal(product.id)}
onClose={this.closeModal}