I'm making a small TODO list project and I hit the wall. I created a form that is responsible for adding new tasks on the list. It consists of two inputs - one for the task name and the other one for the description. There's also an image submit input.
The problem is that only the first item is appended. Another entries just replace the current one. I was trying to somehow gather all of these into one array and map but was unsuccessful. Perhaps it's a couple of lines of code to make this work properly and I'm missing something. Please take a look:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import addStaticButton from './images/addStaticBtn.png';
import addButton from './images/addTaskBtn.png';
var todoContainer = document.getElementById('todo');
class AddTaskElement extends Component {
render() {
const styling = {
addTaskContainer: {
border: "2px solid #000",
width: "350px",
cursor: 'pointer',
boxSizing: 'border-box'
},
leftArea: {
position: 'relative',
float: 'left',
marginRight: '20px',
padding: '12px'
},
addStaticBtn: {
width: '50px',
height: '50px'
}
}
return (
<div style={styling.addTaskContainer} onClick={this.props.isAddTaskClicked} className="addTaskContainer">
<div style={styling.leftArea} className="leftArea">
<img style={styling.addStaticBtn} id="addStaticBtn" alt="addStaticBtn" src={addStaticButton}/>
</div>
<div className="rightArea">
<h1 id="addTaskText">ADD TASK</h1>
</div>
</div>
);
}
}
class TaskInfo extends Component {
constructor(props) {
super(props);
}
render() {
const styling = {
taskInfoContainer: {
border: "2px solid #000",
boxSizing: 'border-box',
width: '350px'
},
taskNameContainer: {
padding: '10px',
},
taskDescriptionContainer: {
padding: '10px'
},
label: {
width: '100px',
display: 'inline-block'
},
taskName: {
width: '220px'
},
taskDescription: {
width: '220px',
height: '75px'
},
addTaskBtn: {
width: '50px',
height: '50px'
},
addTaskBtnContainer: {
textAlign: 'center'
}
}
return(
<div style={styling.taskInfoContainer} className={this.props.taskElementItemClass}>
<form onSubmit={this.props.formSubmit}>
<div className="taskNameContainer" style={styling.taskNameContainer}>
<label style={styling.label}>Name: </label>
<input id="taskName" style={styling.taskName} name="name" type="text" />
</div>
<div style={styling.taskDescriptionContainer} className="taskDescriptionContainer">
<label style={styling.label}>Description: </label>
<textarea id="taskDescription" style={styling.taskDescription} ></textarea>
</div>
<div style={styling.addTaskBtnContainer}>
<input style={styling.addTaskBtn} type="image" src={addButton} alt="Add Task" />
</div>
</form>
</div>
);
}
}
class TaskItem extends Component {
render() {
return(
<div>
{/*{this.props.children}*/}
<p>{this.props.taskItemName}</p>
<p>{this.props.taskItemDescription}</p>
</div>
);
}
}
class TaskList extends Component {
static defaultProps = {
numberOfTasks: 0
}
render() {
const styling = {
taskListContainer: {
width: '350px',
border: '2px solid #000',
boxSizing: 'border-box',
textAlign: 'center'
}
};
return(
<div>
<div className="taskListContainer" style={styling.taskListContainer}>
<p>Task List ({this.props.numberOfTasks})</p>
<TaskItem taskItemName={this.props.taskItemName} taskItemDescription={this.props.taskItemDescription} />
</div>
</div>
);
}
}
class Printer extends Component {
constructor(props) {
super(props);
this.state = {
taskElementItemState: 'hidden',
taskName: '',
taskDescription: ''
}
this.handleAddTaskClick = this.handleAddTaskClick.bind(this);
this.handleTaskAdd = this.handleTaskAdd.bind(this);
}
handleTaskAdd(e) {
e.preventDefault();
this.setState({
taskName: document.getElementById('taskName').value,
taskDescription: document.getElementById('taskDescription').value
});
}
handleAddTaskClick() {
this.setState({
taskElementItemState: this.state.taskElementItemState === 'hidden' ? 'visible' : 'hidden'
});
}
render() {
return(
<div>
<AddTaskElement isAddTaskClicked={this.handleAddTaskClick}/>
<TaskInfo formSubmit={this.handleTaskAdd} taskElementItemClass={this.state.taskElementItemState}/>
<TaskList taskItemName={this.state.taskName} taskItemDescription={this.state.taskDescription} />
</div>
);
}
}
ReactDOM.render(<Printer/>, todoContainer);
Related
There are many packages available to navigate between sections on same page. But I don't want to integrate any package as dependency for doing a simple task. Here is a sample code for navigation which is not dynamic
import React, { useRef } from "react";
function Navigation() {
const top = useRef(null);
const scrollAnySection = (ref) => {
window.scrollTo({
top: ref.current.offsetTop - 10,
behavior: 'smooth',
});
};
return (
<>
<div className="navigation" style={{ width: "80%", margin: "3rem auto" }}>
<section className="menu--container">
<h3 onClick={() => scrollAnySection(top)}>Top</h3>
</section>
<section>
<h3 ref={top} className="section--items"
style={{ margin:"100rem 0",textAlign:"center",border:"1px solid blue" }}> Top </h3>
</section>
</div>
</>
);
}
export default Navigation;
But I am getting difficulty with dynamic useRef here where the ref of HTML element will be called from an array. Below is a sample what I am trying to do for dynamic contents. But I am not getting the expected result.
import React, { useRef } from "react";
function Navigation() {
const listSection = ["Head", "Body", "Main", "Footer", "Bottom"];
const navigateToSection = useRef([]);
const scrollAnySection = (ref) => {
window.scrollTo({
top: ref.current.offsetTop - 10,
behavior: 'smooth',
});
};
return (
<>
<div className="navigation" style={{ width: "80%", margin: "3rem auto" }}>
<section className="menu--container" style={{ display: "flex", justifyContent: "space-between"}}>
{ listSection.map((item) => (
<h3
style={{ padding: ".5rem 2rem", borderRadius: "25rem", border: "1px solid blue" }}
className="menu--items"
onClick={() => scrollAnySection ({ item }) }
>{ item }</h3>
))
}
</section>
<section>
{ listSection.map((item, index) => (
<h3
className="section--items"
style={{ margin: "100rem 0", textAlign: "center", border: "1px solid blue" }}
ref={ ref => { navigateToSection.current[index] = ref; }}
>This is { item } section</h3>
))
}
</section>
</div>
</>
);
}
export default Navigation;
I am getting Uncaught TypeError: ref.current is undefined at scrollAnySection and onClick() event.
Any suggestion or a better approach will be appreciated. Thanks.
Im having issues with closing the tour. Clicking on the "Skip tour" leads to the next step... Why? Why it doesnt close the tooltip?
Sample:
const App = () => {
const steps = [];
return (
<div>
<div style={{ background: 'yellow' }} className={'a'}>
hey
</div>
<div style={{ background: 'green' }} className={'b'}>
hey
</div>
<div style={{ background: 'red' }} className={'c'}>
hey
</div>
<Joyride steps={steps} tooltipComponent={CustomTooltip} />
</div>
);
};
const CustomTooltip = ({
index,
size,
step,
closeProps,
primaryProps,
tooltipProps,
isLastStep,
}) => (
<div {...tooltipProps} style={{ background: 'blue', padding: '20px' }}>
<button {...closeProps}>Skip Tour</button>
<button {...primaryProps}>{isLastStep ? 'Close' : 'Next'}</button>
</div>
);
Playground: https://codesandbox.io/s/boring-carson-fmrfo?file=/src/index.tsx
Docs: https://docs.react-joyride.com/custom-components
What you need is skipProps not closeProps. Replace both instances of the variable and you should be good.
import React from "react";
import ReactDOM from "react-dom";
import "react-app-polyfill/ie11";
import "core-js/stable";
import "regenerator-runtime/runtime";
import "polyfill-array-includes";
import Joyride from "react-joyride";
const CustomTooltip = ({
index,
size,
step,
skipProps,
primaryProps,
tooltipProps,
isLastStep
}) => (
<div {...tooltipProps} style={{ background: "blue", padding: "20px" }}>
<button {...skipProps}>Skip Tour</button>
<button {...primaryProps}>{isLastStep ? "Close" : "Next"}</button>
</div>
);
const App = () => {
const steps = [
{
target: ".a",
title: "",
content: "a",
placement: "bottom-start",
disableBeacon: true
},
{
target: ".b",
title: "",
content: "b",
placement: "bottom-start",
disableBeacon: true
},
{
target: ".c",
title: "",
content: "c",
placement: "bottom-start",
disableBeacon: true
}
];
return (
<div>
<div style={{ background: "yellow" }} className={"a"}>
hey
</div>
<div style={{ background: "green" }} className={"b"}>
hey
</div>
<div style={{ background: "red" }} className={"c"}>
hey
</div>
<Joyride steps={steps} tooltipComponent={CustomTooltip} />
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
https://codesandbox.io/s/compassionate-gagarin-3skx6?file=/src/index.tsx
My goal is to create a border radius previewer where the user defines the affect of the border radius. When I try to make an input nothing happens when I put in a value. When I delete the value I typed in, then the default value change disappears.
I've tried to modify the code and I've tried searching other questions and answers but I haven't found a solution.
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
topleft: 30,
topright: 30,
bottomright: 30,
bottomleft: 30
}
}
handleChange = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({[nam]: val});
}
render() {
const borderStyle = {
borderRadius: this.state.topleft,
background: "#73AD21",
padding: "20px",
width: "200px",
height: "150px",
}
return (
<div className="App">
<h1>Border-Radius Previewer</h1>
<p style={borderStyle}>Box</p>
<p>Border-Radius Values:</p>
<input type="number" name="topleft" onChange={this.handleChange} />
<input type="number" name="topright" onChange={this.handleChange} />
<input type="number" name="bottomright" onChange={this.handleChange} />
<input type="number" name="bottomleft" onChange={this.handleChange} />
</div>
);
}
}
export default App;
numbered string is not recognized for inline style.
borderRadius: "100" means nothing
You should either write
borderRadius: "100px" or borderRadius: 100
You can simply update handleChange function to keep only number as the state value.
Updated Code
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
topleft: 30,
topright: 30,
bottomright: 30,
bottomleft: 30
}
}
handleChange = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({[nam]: Number(val)});
}
render() {
const borderStyle = {
borderRadius: this.state.topleft,
background: "#73AD21",
padding: "20px",
width: "200px",
height: "150px",
}
return (
<div className="App">
<h1>Border-Radius Previewer</h1>
<p style={borderStyle}>Box</p>
<p>Border-Radius Values:</p>
<input type="number" name="topleft" onChange={this.handleChange} />
<input type="number" name="topright" onChange={this.handleChange} />
<input type="number" name="bottomright" onChange={this.handleChange} />
<input type="number" name="bottomleft" onChange={this.handleChange} />
</div>
);
}
}
export default App;
I supposed you want to apply topleft, topright, bottomright and bottomleft states as borderRadius — you could use string interpolation to append px on each value.
const { topleft, topright, bottomright, bottomleft } = this.state;
const borderStyle = {
borderRadius: `${topleft}px ${topright}px ${bottomright}px ${bottomleft}px`,
background: "#73AD21",
padding: "20px",
width: "200px",
height: "150px"
};
<script src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/#babel/standalone/babel.min.js"></script>
<div id="app_root"></div>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
topleft: 30,
topright: 30,
bottomright: 30,
bottomleft: 30
};
}
handleChange = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({ [nam]: val });
};
render() {
const { topleft, topright, bottomright, bottomleft } = this.state;
const borderStyle = {
borderRadius: `${topleft}px ${topright}px ${bottomright}px ${bottomleft}px`,
background: "#73AD21",
padding: "20px",
width: "200px",
height: "150px"
};
return (
<div className="App">
<h1>Border-Radius Previewer</h1>
<p style={borderStyle}>Box</p>
<p>Border-Radius Values:</p>
<input type="number" name="topleft" onChange={this.handleChange} />
<input type="number" name="topright" onChange={this.handleChange} />
<input type="number" name="bottomright" onChange={this.handleChange} />
<input type="number" name="bottomleft" onChange={this.handleChange} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("app_root"));
</script>
So what you have to do brother is append a string to the state when you are setting the state and that is how 'px' is added.Complete code
class App extends Component {
constructor(props) {
super(props)
this.state = {
topleft: '30px',
topright: '30px',
bottomright: '30px',
bottomleft: '30px'
}
}
handleChange = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({[nam]: val+'px'});
}
render() {
console.log(this.state.topleft);
const borderStyle = {
borderRadius: this.state.topleft,
background: "#73AD21",
padding: "20px",
width: "200px",
height: "150px",
}
return (
<div className="App">
<h1>Border-Radius Previewer</h1>
<p style={borderStyle}>Box</p>
<p>Border-Radius Values:</p>
<input type="string" name="topleft" onChange={this.handleChange} />
<input type="string" name="topright" onChange={this.handleChange} />
<input type="string" name="bottomright" onChange={this.handleChange} />
<input type="string" name="bottomleft" onChange={this.handleChange} />
</div>
);
}
}
export default App;
Hello i wanted to make a toggle button menu
ie by clicking on the button the div would increase the height with some transition
but I can't imagine how to do this in react
function App() {
const handleClick = e => {
e.preventDefault();
};
return (
<div
className="Wrapper"
style={{
backgroundColor: "#000",
height: "30px",
width: "200px"
}}
>
<Button
style={{ padding: 0, height: "30px", width: "200px" }}
circular
icon="settings"
onClick={handleClick}
>
Button
</Button>
</div>
);
}
my codebox: https://codesandbox.io/s/funny-minsky-j9x6x
You need to add a state variable to your function. You can now use hooks for that.
import React from "react";
import ReactDOM from "react-dom";
import { Button } from "semantic-ui-react";
import "./styles.css";
import { useState } from 'react';
function App() {
const [open, setOpen] = useState(0); // declare new state variable "open" with setter
const handleClick = e => {
e.preventDefault();
setOpen(!open);
};
return (
<div
className="Wrapper"
style={{
backgroundColor: "#000",
height: (open ? "400px" : "30px"), // make the div tall when "open"
width: "200px",
transition: "height 1s" // transition for 1 second
}}
>
<Button
style={{ padding: 0, height: "30px", width: "200px" }}
circular
onClick={handleClick}
>
Button
</Button>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
what I want is to change the background color of the chip depending on whether user admin or not, a different color for each user, in the list of comments, so that the end user can define who is the admin and who is not.
this is my code
import React from 'react';
import TimeAgo from 'react-timeago';
import PropTypes from 'prop-types';
import Card from 'components/commons/Card';
import Chip from '#material-ui/core/Chip';
import Button from '#material-ui/core/Button';
import { Grid } from '#material-ui/core';
import { withRouter } from 'react-router-dom';
import { connect } from 'react-redux';
import { getComments } from 'api'
const styles = {
root: {
paddingTop: '25px',
color: '#FFFFFF'
},
chipA: {
color: 'white',
fontWeight: 'bold',
backgroundColor: '#00a6ff',
textTransform: 'uppercase',
fontSize: '1rem',
letterSpacing: '0px',
textAlign: 'center'
},
chipB: {
color: 'primary',
fontWeight: 'bold',
backgroundColor: '#ff8400',
textTransform: 'uppercase',
fontSize: '1rem',
letterSpacing: '0px',
textAlign: 'center'
},
Button: {
fontWeight: 'bold',
fontSize: '1rem',
letterSpacing: '0px',
textTransform: 'uppercase',
borderRadius: '2.5px',
textAlign: 'center',
},
};
class Comment extends React.Component {
constructor(props) {
super(props);
this.state = {
comment: '',
isAdmin: [],
};
}
componentDidMount() {
console.log(this.props.isAdmin)
if (this.props.isAdmin) {
console.log('Admin User');
}else {
console.log('Normal User');
}
};
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
}
renderComments(comments) {
const condition = this.props.isAdmin;
console.log(condition);
const commentDivs = comments.map(user => {
return (
<div key={user.id}>
<div className="row">
<div className="col comment">{user.description}</div>
</div>
<div className="row">
<div className="col-9">
<TimeAgo className="time-ago" date={user.createdAt} />
</div>
<div className="col-3">
<div style={styles.wrapper}>
<span className="time-ago">
<Chip
label={user['user.firstname'] + ' ' + user['user.lastname']}
style={{ backgroundColor: condition ? "#00a6ff" : "#ff8400" , color: 'white', fontWeight: 'bold',
textTransform: 'uppercase',
fontSize: '1rem',
letterSpacing: '0px',
textAlign: 'center'}}
/>
</span>
</div>
</div>
</div>
<hr />
</div>
)
});
return (
<div>{commentDivs}</div>
);
}
render() {
return (
<Card title="comments">
<Grid item xs={12} md={12}>
{this.renderComments(this.props.comments)}
<div className="form-group">
<textarea
className="form-control"
name="comment"
placeholder="Write a comment"
onChange={this.onChange}
value={this.state.comment}
rows="3"
></textarea>
</div>
<div className="form-group">
<Button
onClick={() => this.props.onSubmit(this.state.comment)}
color="primary"
variant="contained"
size="large"
style={styles.Button}>
Send
</Button>
</div>
</Grid>
</Card>
);
}
}
Comment.propTypes = {
comments: PropTypes.array.isRequired,
onSubmit: PropTypes.func.isRequired,
isAdmin: PropTypes.bool,
};
const mapStateToProps = state => {
return {
isAdmin: state.auth.isAdmin,
};
};
export default withRouter(connect(mapStateToProps, {
})(Comment)) ;
what I define is that I change the color depends on who is registered, but what you want is to identify who is admin or not in any of the two users, whether admin or normal user.
this is my result