I am new to React.js and trying to create a TODO list. I have two buttons for edit and delete. Delete button is working fine, but not the edit button. I am having a hard time with Edit button. When I click on the edit button, I want the text box to be editable. Then I can edit and when I enter, it should be updated.
I have some css issue with button alignments too. Please help me with this.
App.js
import React from 'react';
import './App.css';
import './AddedTasks.css'
import uuid from 'uuid'
class App extends React.Component{
constructor(props){
super(props);
this.state = {
task:[],
currentTask:{
text:'',
key:''
}
}
this.addTask = this.addTask.bind(this);
this.editTask = this.editTask.bind(this);
this.deleteTask = this.deleteTask.bind(this);
this.handleInput = this.handleInput.bind(this);
}
addTask(event){
event.preventDefault();
const newItem = this.state.currentTask;
if(newItem.text !==""){
const items = [...this.state.task, newItem];
this.setState({
task: items,
currentTask:{
text:'',
key:''
},
})
}
}
editTask(text,key) {
//console.log("items:"+this.state.task);
const items = this.state.task;
items.map(item=>{
if(item.key===key){
//console.log(item.key +" "+key)
// item.text= text.title;
}
})
this.setState({
task: items,
})
}
deleteTask(key){
const currentTaskArray = [...this.state.task]
const taskAfterDeleted = currentTaskArray.filter(deletedTask => deletedTask.key !== key);
this.setState({
task:taskAfterDeleted
})
}
handleInput(event){
this.setState({
currentTask:{
text: event.target.value,
key: uuid()
}
})
}
render(){
return(
<div className='Todo'>
<h1> MyTaskList </h1>
<form id="todo-list" onSubmit={this.addTask}>
<input type="text" className="textInput" placeholder="Enter Item" value={this.state.currentTask.text} onChange={this.handleInput}/>
<button type ="submit">Add</button>
</form>
{this.state.task.map(oneTask=>(
<div className="card">
<div className="container">
<p>{oneTask.text}
<div>
<button className="w3-button delete" onClick={()=> this.deleteTask(oneTask.key)}><i className="fa fa-trash"/></button>
<button className="w3-button edit" onClick={(edit)=>this.editTask(edit.target.value,oneTask.key)}><i className="glyphicon glyphicon-pencil"/></button>
</div>
</p>
</div>
</div>
))}
</div>
);
}
}
export default App;
App.css
_______________
body{
background-color: lightblue;
background-image: url("./todolist.jpg");
background-repeat: no-repeat;
background-size: cover;
alignment: center;
padding-top: 40px;
}
h1{
text-align: center;
color: #bf6318;
padding-right: 17px;
}
.Todo{
background-color: #c1b2cd;
min-height: 500px;
width: 500px;
margin: 150px;
padding-left: 20px;
background-image: url("./pin.jpg");
background-size: 80px;
background-repeat: no-repeat;
}
#todo-list input{
background-color: rgb(95, 83, 135);
border: 0;
width: 250px;
height: 50px;
padding: 0 20px;
margin: 20px;
font-size: 18px;
border-radius: 10px;
color: #ffffff;
}
#todo-list input::placeholder{
color: rgba(255,255,255,0.5);
}
button{
background-color: #008CBA;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
-webkit-transition-duration: 0.4s; /* Safari */
transition-duration: 0.4s;
box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
}
AddedTask.cs
_________________
.card {
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
transition: 0.3s;
width: 70%;
border-radius: 5px;
margin-bottom: 10px;
margin-left: 20px;
background-color: #bf826b;
}
.card:hover {
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
}
.container {
padding: 4px 16px; /*input/card field*/
height: 40px;
}
.container button.edit{
color: #bf6318;
margin-left: 80px;
margin-right: 10px;
}
.container button.delete{
}
The edit button is not working because you are using edit.target.value which doesn't exist. In my understanding, you are trying to access the text so it will be oneTask.text.
Here is the file:
App.js
import React from "react";
import "./styles.css";
import uuid from "uuid";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
task: [],
currentTask: {
text: "",
key: ""
}
};
this.addTask = this.addTask.bind(this);
this.editTask = this.editTask.bind(this);
this.deleteTask = this.deleteTask.bind(this);
this.handleInput = this.handleInput.bind(this);
}
addTask(event) {
event.preventDefault();
const newItem = this.state.currentTask;
if (newItem.text !== "") {
const items = [...this.state.task, newItem];
this.setState({
task: items,
currentTask: {
text: "",
key: ""
}
});
}
}
editTask(text, key) {
//console.log("items:"+this.state.task);
const items = this.state.task;
this.setState({
task: items.filter(item => item.key !== key),
currentTask: {
text
}
});
}
deleteTask(key) {
const currentTaskArray = [...this.state.task];
const taskAfterDeleted = currentTaskArray.filter(
deletedTask => deletedTask.key !== key
);
this.setState({
task: taskAfterDeleted
});
}
handleInput(event) {
this.setState({
currentTask: {
text: event.target.value,
key:uuid()
}
});
}
render() {
return (
<div className="Todo">
<h1> MyTaskList </h1>
<form id="todo-list" onSubmit={this.addTask}>
<input
type="text"
className="textInput"
placeholder="Enter Item"
value={this.state.currentTask.text}
onChange={this.handleInput}
/>
<button type="submit">Add</button>
</form>
{this.state.task.map(oneTask => (
<div key={oneTask.key} className="card">
<div className="container">
<p>
{oneTask.text}
<div>
<button
className="w3-button delete"
onClick={() => this.deleteTask(oneTask.key)}
>
Delete
</button>
<button
className="w3-button edit"
onClick={() => this.editTask(oneTask.text, oneTask.key)}
>
Edit
</button>
</div>
</p>
</div>
</div>
))}
</div>
);
}
}
export default App;
I have also manipulated the edit task code you can revert back to use your code.
Here is the working link: https://codesandbox.io/s/gifted-almeida-uivq0
Hope this helps!
So I'm assuming that this is a view of todo and by default it's disabled. You can use a state variable to make textboxes enabled when clicking on the edit button.
Add a handler to edit button click event and inside this handler change state variable. So react will enable those two textboxes based on that event.
this.state = {
isEditable:false // by defualt this is disables
}
editHandler(){
//change isEditable to true
}
Make sure to bind this new method in constructor. Then add this to the button click event.
Base on isEditable makes your form controls enabled or disabled.
Regarding CSS, just use a new div element and inside that div include two buttons. So it won't come to on top of text boxes.
<div>
<div>text box and button</div>
<div>second row</div>
<div>edit and delete button></div>
</div>
Related
Hi I'm trying to configure the colour of a button base on it's button type which will be put in a modal. In this case, either "Success" or "Danger":
import React from "react";
import styled from "styled-components";
const ButtonStyled = styled.button`
background-color: ${(props) =>
props.btnType === "Success" ? "green" : "red"};
border: none;
color: white;
outline: none;
cursor: pointer;
font: Regular 400;
padding: 0.5rem 0;
margin: 0.5rem 1rem;
font-weight: bold;
margin-left: 0;
padding-left: 0;
`;
const Button = (props) => {
console.log(props.btnType);
return (
<ButtonStyled btnType={props.btnType} onClick={props.clicked}>
{props.children}
</ButtonStyled>
);
};
export default Button;
Here's where I called the button:
import React from "react";
import Button from "../../UI/Button/Button";
const OrderSummary = (props) => {
return (
<div>
<Button btnType="Danger" clicked={props.cancelPurchase}>
Cancel
</Button>
<Button btnType="Success" clicked={props.continuePurchase}>
Continue
</Button>
</div>
);
};
export default OrderSummary;
Here is where the Order Summary being called:
import React, { useState } from "react";
import Modal from "../../components/UI/Modal/Modal";
import OrderSummary from "../../components/Burger/OrderSummary/OrderSummary";
const INGREDIENT_PRICES = {
salad: 0.5,
cheese: 0.4,
meat: 1.3,
bacon: 0.7,
};
const BurgerBuilder = () => {
const [ingredients, setIngredients] = useState({
salad: 0,
bacon: 0,
cheese: 0,
meat: 0,
});
const [totalPrice, setTotalPrice] = useState(4);
const [purchasing, setPurchasing] = useState(false);
const purchaseCancelHandler = () => {
setPurchasing(false);
};
const purchaseContinueHandler = () => {
alert("continue");
};
return (
<div>
<Modal show={purchasing} modalClosed={purchaseCancelHandler}>
<OrderSummary
continuePurchase={purchaseContinueHandler}
cancelPurchase={purchaseCancelHandler}
ingredients={ingredients}
price={totalPrice.toFixed(2)}
/>
</Modal>
</div>
);
};
export default BurgerBuilder;
Down here is the modal where the Button being applied
import React from "react";
import styled from "styled-components";
import Backdrop from "../Backdrop/Backdrop";
const ModalWrapper = styled.div`
box-shadow: 0 5px 16px rgba(0, 0, 0, 0.2);
background: #fff;
justify-content: center;
align-items: center;
color: #000;
display: grid;
grid-template-columns: 1fr 1fr;
position: fixed;
z-index: 500;
border-radius: 10px;
transition: all 0.3s ease-out;
padding: 16px;
left: 15%;
top: 30%;
#media (min-width: 600px) {
width: 500px;
left: calc(50% - 250px);
}
`;
const ModalContent = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
line-height: 1.8;
color: #141414;
p {
margin-bottom: 1rem;
}
button {
padding: 10px 24px;
background: #141414;
// color: #fff;
border: none;
}
`;
const Modal = (props) => {
return (
<div>
<Backdrop show={props.show} clicked={props.modalClosed} />
<ModalWrapper
style={{
transform: props.show ? "translateY(0)" : "translateY(-100vh)",
opacity: props.show ? "1" : "0",
}}
>
<ModalContent>{props.children}</ModalContent>
</ModalWrapper>
</div>
// <ModalStyled>{props.children}</ModalStyled>
);
};
export default Modal;
As I did some testing, the values in the styled component Modal Content which state the button in that content will be that. Hence it affected the value of the styled component Button Styled. However, if I removed the value of button in Modal Content, the value of the color in ButtonStyled won't be accepted. Does anyone happen to know why?
The button style defined in the ModalContent is overriding the button style you've defined in your Button component.
button {
padding: 10px 24px;
background: #141414; // <-- overrides button background color
border: none;
}
With CSS the most specific selector will be the one that sets the style and I suspect the ModalContent styled component's computed style results with a more specific selector for button elements than the one from ButtonStyled.
What you can do is bump the selector specificity of the ButtonStyled background color.
Pseudoelements, pseudoselectors, and nesting, the last section.
Finally, the ampersand can be used to increase the specificity of
rules on the component; this can be useful if you are dealing with a
mixed styled-components and vanilla CSS environment where there might
be conflicting styles
const ButtonStyled = styled.button`
&& {
background-color: ${(props) =>
props.btnType === "Success" ? "green" : "red"};
}
border: none;
color: white;
outline: none;
cursor: pointer;
font: Regular 400;
padding: 0.5rem 0;
margin: 0.5rem 1rem;
font-weight: bold;
margin-left: 0;
padding-left: 0;
`;
I'm quite new to react and a simple slot machine is my first mini-project. Currently I have completed the logic for displaying random emojis after the button is pressed. The next step for me, before styling and adding logic for winning/losing and a counter for coins etc is adding an animation.
https://codepen.io/fmressel/pen/vRLerN
This codepen is exactly the sort of thing I'm after, but as you can see it is structured quite differently to my code (below), and I'm pulling my hair out trying to figure out how I can get something similar to work for my project.
Any help much appreciated!
import React, { Component } from 'react'
import Contents from './Contents'
import './mainslots.css'
class Slots extends Component {
static defaultProps = {
fruits: ["π", "π", "π", "π", "π", "π₯"]
};
constructor(props) {
super(props);
this.state = {fruit1: 'π', fruit2: 'π', fruit3: 'π', rolling: false};
this.roll = this.roll.bind(this);
};
roll = () => {
const dFruit1 = this.props.fruits[
Math.floor(Math.random() * this.props.fruits.length)
];
const dFruit2 = this.props.fruits[
Math.floor(Math.random() * this.props.fruits.length)
];
const dFruit3 = this.props.fruits[
Math.floor(Math.random() * this.props.fruits.length)
];
this.setState({fruit1: dFruit1, fruit2: dFruit2, fruit3: dFruit3, rolling: true});
setTimeout(() => {
this.setState({ rolling: false });
}, 700)
}
render(){
return(
<div className="SlotMachine">
<div className="SlotsContainer">
{this.state.fruit1}
{this.state.fruit2}
{this.state.fruit3}
</div>
<button className="spinner" onClick={this.roll} disabled={this.state.rolling}>
{this.state.rolling ? "Spinning..." : "Spin"}
</button>
</div>
);
}
}
export default Slots;
import React, { Component } from 'react'
class Contents extends Component {
Fruits = ["π", "π", "π", "π", "π", "π₯"];
render() {
return(
<div className="emptys">
{this.props.roll}
</div>
)
}
}
export default Contents
Here you go,
It was fun to develop :), you can run the below code snippet to review and I've added the comments in code, that will make things clear, please have a look,
Hope this will help,
const { createRef , Component } = React;
class Slots extends Component {
static defaultProps = {
fruits: ["π", "π", "π", "π", "π", "π₯"]
};
constructor(props) {
super(props);
this.state = { fruit1: "π", fruit2: "π", fruit3: "π", rolling: false };
// get ref of dic onn which elements will roll
this.slotRef = [createRef(), createRef(), createRef()];
}
// to trigger roolling and maintain state
roll = () => {
this.setState({
rolling: true
});
setTimeout(() => {
this.setState({ rolling: false });
}, 700);
// looping through all 3 slots to start rolling
this.slotRef.forEach((slot, i) => {
// this will trigger rolling effect
const selected = this.triggerSlotRotation(slot.current);
this.setState({ [`fruit${i + 1}`]: selected });
});
};
// this will create a rolling effect and return random selected option
triggerSlotRotation = ref => {
function setTop(top) {
ref.style.top = `${top}px`;
}
let options = ref.children;
let randomOption = Math.floor(
Math.random() * Slots.defaultProps.fruits.length
);
let choosenOption = options[randomOption];
setTop(-choosenOption.offsetTop + 2);
return Slots.defaultProps.fruits[randomOption];
};
render() {
return (
<div className="SlotMachine">
<div className="slot">
<section>
<div className="container" ref={this.slotRef[0]}>
{Slots.defaultProps.fruits.map((fruit, i) => (
<div key={i}>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={this.slotRef[1]}>
{Slots.defaultProps.fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={this.slotRef[2]}>
{Slots.defaultProps.fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div
className={!this.state.rolling ? "roll rolling" : "roll"}
onClick={!this.state.rolling && this.roll}
disabled={this.state.rolling}
>
{this.state.rolling ? "Rolling..." : "ROLL"}
</div>
</div>
);
}
}
ReactDOM.render(<Slots />, document.getElementById('react-root'));
.App {
font-family: sans-serif;
text-align: center;
}
.slot {
position: relative;
display: inline-block;
height: 100px;
width: 80px;
}
section {
position: absolute;
border-radius: 15px !important;
border: 3px solid black !important;
width: 70px;
height: 70px;
overflow: hidden;
background-color: grey;
border-radius: 2px;
border: 1px solid lightgrey;
color: white;
font-family: sans-serif;
text-align: center;
font-size: 25px;
line-height: 60px;
cursor: default;
}
.container {
position: absolute;
top: 2px;
width: 100%;
transition: top ease-in-out 0.5s;
text-align: center;
}
.roll {
width: 215px;
cursor: pointer;
background-color: yellow;
padding: 10px;
text-align: center;
font-size: 20px;
border-radius: 20px;
border: 3px solid black;
}
.rolling {
animation: blinkingText 1.2s infinite;
}
#keyframes blinkingText {
0% {
color: #000;
}
49% {
color: #000;
}
60% {
color: transparent;
}
99% {
color: transparent;
}
100% {
color: #000;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>
I recreated the #VivekDoshi 's answer as a react FC.
const { useRef, useState} = React;
function Slots(){
const [fruit1,setFruit1] = useState("π");
const [fruit2,setFruit2] = useState("π");
const [fruit3,setFruit3] = useState("π");
const [rolling,setRolling] = useState(false);
let slotRef = [useRef(null), useRef(null), useRef(null)];
const fruits = ["π", "π", "π", "π", "π", "π₯"]
// to trigger roolling and maintain state
const roll = () => {
setRolling(true);
setTimeout(() => {
setRolling(false);
}, 700);
// looping through all 3 slots to start rolling
slotRef.forEach((slot, i) => {
// this will trigger rolling effect
const selected = triggerSlotRotation(slot.current);
if(i+1 == 1)
setFruit1(selected);
else if(i+1 == 2)
setFruit2(selected);
else
setFruit3(selected);
});
};
// this will create a rolling effect and return random selected option
const triggerSlotRotation = ref => {
function setTop(top) {
ref.style.top = `${top}px`;
}
let options = ref.children;
let randomOption = Math.floor(
Math.random() * fruits.length
);
let choosenOption = options[randomOption];
setTop(-choosenOption.offsetTop + 2);
return fruits[randomOption];
};
return (
<div className="SlotMachine">
<div className="slot">
<section>
<div className="container" ref={slotRef[0]}>
{fruits.map((fruit, i) => (
<div key={i}>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={slotRef[1]}>
{fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div className="slot">
<section>
<div className="container" ref={slotRef[2]}>
{fruits.map(fruit => (
<div>
<span>{fruit}</span>
</div>
))}
</div>
</section>
</div>
<div
className={!rolling ? "roll rolling" : "roll"}
onClick={!rolling && roll}
disabled={rolling}>
{rolling ? "Rolling..." : "ROLL"}
</div>
</div>
);
};
ReactDOM.render(<Slots />, document.getElementById('react-root'));
.App {
font-family: sans-serif;
text-align: center;
}
.slot {
position: relative;
display: inline-block;
height: 100px;
width: 80px;
}
section {
position: absolute;
border-radius: 15px !important;
border: 3px solid black !important;
width: 70px;
height: 70px;
overflow: hidden;
background-color: grey;
border-radius: 2px;
border: 1px solid lightgrey;
color: white;
font-family: sans-serif;
text-align: center;
font-size: 25px;
line-height: 60px;
cursor: default;
}
.container {
position: absolute;
top: 2px;
width: 100%;
transition: top ease-in-out 0.5s;
text-align: center;
}
.roll {
width: 215px;
cursor: pointer;
background-color: yellow;
padding: 10px;
text-align: center;
font-size: 20px;
border-radius: 20px;
border: 3px solid black;
}
.rolling {
animation: blinkingText 1.2s infinite;
}
#keyframes blinkingText {
0% {
color: #000;
}
49% {
color: #000;
}
60% {
color: transparent;
}
99% {
color: transparent;
}
100% {
color: #000;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react-root"></div>
I'm new to react, and I'm working on a small project that uses a search bar in Single js Web page to find data from API.
The main code for this component is:
const main = () => {
const searchElement = document.querySelector("search-bar");
const clubListElement = document.querySelector("club-list");
const onButtonSearchClicked = async() => {
try{
const result = await DataSource.searchClub(searchElement.value);
renderResult(result);
} catch (message) {
fallbackResult(message)
}
};
const renderResult = (results) => {
clubListElement.clubs = results;
};
const fallbackResult = message => {
clubListElement.renderError(message);
};
searchElement.clickEvent = onButtonSearchClicked;
};
export default main;
also my Search-Bar component:
class SearchBar extends HTMLElement{
constructor(){
super();
this.shadowDOM = this.attachShadow({mode: "open"});
}
connectedCallback(){
this.render();
}
set clickEvent(event){
this._clickEvent = event;
this.render();
}
get value(){
//return this.querySelector("#searchElement").value;
return this.shadowDOM.querySelector("#searchElement").value;
}
render(){
//this.innerHTML = `
this.shadowDOM.innerHTML = `
<style>
.search-container {
max-width: 800px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
padding: 16px;
border-radius: 5px;
display: flex;
position: sticky;
top: 10px;
background-color: white;
}
.search-container > input {
width: 75%;
padding: 16px;
border: 0;
border-bottom: 1px solid cornflowerblue;
font-weight: bold;
}
.search-container > input:focus {
outline: 0;
border-bottom: 2px solid cornflowerblue;
}
.search-container > input:focus::placeholder {
font-weight: bold;
}
.search-container > input::placeholder {
color: cornflowerblue;
font-weight: normal;
}
.search-container > button {
width: 23%;
cursor: pointer;
margin-left: auto;
padding: 16px;
background-color: cornflowerblue;
color: white;
border: 0;
text-transform: uppercase;
}
#media screen and (max-width: 550px){
.search-container {
flex-direction: column;
position: static;
}
.search-container > input {
width: 100%;
margin-bottom: 12px;
}
.search-container > button {
width: 100%;
}
}
</style>
<div id="search-container" class="search-container">
<input placeholder="Search football club" id="searchElement" type="search">
<button id="searchButtonElement" type="submit">Search</button>
</div>
`;
this.shadowDOM.querySelector("#searchButtonElement").addEventListener("click", this._clickEvent);
}
}
customElements.define("search-bar", SearchBar);
furthermore, can i convert this method to ReactJS? because we know if we can't declare a const in render() from React.
I have been through a bunch of flustered, and I'm not exactly sure how to go about doing that.
Can anyone help me with this please? Any other comments on the code are also welcome because i'm new in Reacts
Thank you before!
First and foremost, you should remove all that CSS declaration within the render method, and abstract them into a separate CSS file (you can consider CSS modules, which is supported by React), use CSS-in-JavaScript libraries(such as styled-components), or inline styles.
Next, instead of using event listeners, you should bind the button element's onClick event with the onButtonSearchClicked method, which is similar to what you have defined.
From that method, you will make the API request, and update your component's state with the response.
class SearchBar extends React.Component {
async onButtonSearchClicked() {
const result = await DataSource.searchClub(searchElement.value);
// set state with return result.
}
render() {
return (
<div id="search-container" class="search-container">
<input placeholder="Search football club" id="searchElement" type="search">
<button id="searchButtonElement" type="submit" onClick={() => this.onButtonSearchClicked}>Search</button>
</div>
);
}
}
One of many variants how could SearchBar component look like in React
class SearchBar extends React.Component {
constructor() {
this.ref = React.createRef(null);
}
componentDidMount() {
this.shadowDOM = this.ref.current.attachShadow({mode: "open"});
this.shadowDOM.innerHTML = getStyle();
}
onClick(event) {
}
render() {
return <div ref={this.ref} id="search-container" class="search-container">
<input placeholder="Search football club" id="searchElement" type="search">
<button onClick={this.onClick} id="searchButtonElement"
type="submit">Search</button>
</div>
}
IΒ΄m trying to do an exercise in React JS "To Do List"
I have to delete some task clicking the trash button, but I donΒ΄t know how to do it, because with my code it is deleting all the task.
Could someone help me and explaining me step by step how to do it? I am a programming begginer student
Here is my code
import React from "react";
//include bootstrap npm library into the bundle
import "bootstrap";
import { EventEmitter } from "events";
//create your first component
export class InputToDo extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
messages: []
};
this.handleChange = this.handleChange.bind(this);
this.keyPressed = this.keyPressed.bind(this);
this.submitMessage = this.submitMessage.bind(this);
this.deleteTask = this.deleteTask.bind(this);
}
handleChange(event) {
this.setState({ input: event.target.value });
}
keyPressed(event) {
if (event.key === "Enter" && event.target.value !== "") {
this.submitMessage();
event.preventDefault();
}
}
submitMessage() {
this.setState({ messages: [...this.state.messages, this.state.input] });
this.setState({ input: "" });
}
deleteTask() {
this.setState({ messages: [] });
}
render() {
return (
<div className="container">
<h2 className="title">
To Do List
<i className="fas fa-tasks" />
</h2>
<input
className="divInput"
placeholder="WhatΒ΄s next to be done?"
onChange={this.handleChange}
onKeyPress={this.keyPressed}
value={this.state.input}
/>
<ul className="list-group">
{this.state.messages.map((item, i) => (
<li className="list-group-item d-flex" key={i}>
{item}
<i
onClick={this.deleteTask}
className="far fa-trash-alt ml-auto"
/>
</li>
))}
</ul>
</div>
);
}
}
#import "~bootstrap/scss/bootstrap.scss";
.main {
margin: 0px;
}
.container {
border-radius: 10px;
border: solid 2px rgb(80, 75, 75);
min-height: 500px;
width: 400px;
margin: 40px auto;
background-color: rgba(230, 255, 253, 0.987);
padding-bottom: 20px;
}
.title {
padding-top: 10px;
text-align: center;
}
.fas {
padding-left: 20px;
}
.divInput {
position: relative;
display: block;
width: 360px;
height: 50px;
padding-top: 0.75rem;
padding-right: 1.25rem;
padding-bottom: 0.75rem;
padding-left: 1.25rem;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.125);
border-bottom-right-radius: 0.25rem;
border-bottom-left-radius: 0.25rem;
}
.list-group-item {
width: 360px;
}
.far {
color:red;
align-content: right;
cursor: pointer;
}
//import react into the bundle
import React from "react";
import ReactDOM from "react-dom";
//include bootstrap npm library into the bundle
import "bootstrap";
//include your index.scss file into the bundle
import "../styles/index.scss";
//import your own components
import { InputToDo } from "./component/InputToDo.js";
//render your react application
ReactDOM.render(<InputToDo />, document.querySelector("#app"));
First thing you need to do is to pass the index of the element in the deleteTask function call:
<i
onClick={() => this.deleteTask(i)}
className="far fa-trash-alt ml-auto"
/>
Then you can remove the item from the state with the deleteTask function as follows:
deleteTask(i) {
const messages = this.state.messages.filter((_, index) => index !== i)
this.setState({ messages });
}
I am working on a React application and I am using Redux to store the state. I have the following code:
request.component.jsx:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import Loading from '../loading/loading.component';
import { changeRequestStatus } from '../../redux/requests/requests.actions';
import { RESOLVED, AWAITING_WAIT_STAFF } from '../../redux/requests/requests.status-types'
import './request.styles.scss';
class Request extends Component {
state = { isLoading: false }
render() {
const { _id, table_no, timestamp, description, status } = this.props.request;
const { user, changeRequestStatus } = this.props;
return (
<>
{this.state.isLoading ? <Loading /> : null}
<div className="request-box">
<div className="request-details">
<div>
<h1 style={{ color: status === AWAITING_WAIT_STAFF ? "#28bfa6" : "#f5a953" }}>Table {table_no}, {new Date(timestamp).toLocaleString()}</h1>
<h2>{description}</h2>
</div>
<div className="status-button">
<button
className="request-button"
onClick={async () => {
this.setState({ isLoading: true })
await changeRequestStatus(_id, status === AWAITING_WAIT_STAFF ? user.username : RESOLVED)
this.setState({ isLoading: false })
}} style={{ background: status === AWAITING_WAIT_STAFF ? "linear-gradient(to right, rgba(141,227,227,1) 0%, rgba(114,240,218,1) 100%)" : "linear-gradient(to right, rgba(255,213,94,1) 0%, rgba(246,170,123,1) 100%)" }}>
{status}
</button>
</div>
</div>
</div>
</>
)
}
}
const mapStateToProps = (state) => {
return {
requests: state.requests.requests,
user: state.user.currentUser
}
}
export default connect(mapStateToProps, { changeRequestStatus })(Request);
request.styles.scss:
.request-box {
border: 1px solid #c3c9c8;
height: 200px;
max-width: 100%;
border-radius: 5px;
position: relative;
background-color: white;
font-family: Helvetica;
box-shadow: 0 10px 6px -6px #ededed;
margin: 10px;
}
.request-details {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
padding: 0 30px;
height: 100%;
h1 {
font-size: 30px;
color: #28bfa6;
text-align: left;
}
h2 {
font-size: 22px;
text-align: left;
}
}
.status-button {
padding-bottom: 25px;
width: 100%;
#media (min-width: 1000px) {
width: auto;
padding-right: 20px;
padding-left: 100px;
}
}
.request-button {
height: 50px;
font-size: 19px;
font-weight: 600;
border: none;
border-radius: 5px;
padding: 10px 25px;
background-size: 150% auto;
background: linear-gradient(to right, rgba(141,227,227,1) 0%, rgba(114,240,218,1) 100%);
cursor: pointer;
&:hover {
background: #2de1c2;
}
}
In my Request component, I am changing the background property of my request-button div depending on the value of the status variable.
However, I would like to change the request-buttton:hover property depending on the value of status variable in my Request component.
I am not sure what the correct syntax would be to achieve this. Any insights are appreciated.
Create different CSS classes for each button color/status. Then use a ternary operator to apply the CSS class to the button when status changes. Check the status via Redux and then apply a CSS className like this.