What is static site generation? - javascript

I know that static site generation idea, The question here is, if SSG gets fetched data at build time, in my next app I used an event handler to get some data according to the search keyword, and it works, How.
This is my code:
Below is the code for the Input component in the next weather app and I use handleSubmit event handler, It gets weather data from an API endpoint.
import React, { useState } from "react";
import PropTypes from "prop-types";
import axios from "axios";
function Input({ onInput }) {
const [inputText, setInputText] = useState();
const [placeholder, setPlaceholder] = useState("أخل اسم البلد أو المنطقة...");
return (
<form className="hstack gap-3" onSubmit={handleSubmit}>
<input
type="text"
className="form-control me-auto"
placeholder={placeholder}
value={inputText || ""}
onChange={handleInput}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<button type="submit">ابحث</button>
<style jsx>{`
input {
height: 50px;
border-radius: 10px;
color: var(--input-color);
font-weight: 500;
font-size: 1.1em;
direction: rtl;
}
input:focus-visible {
color: var(--input-color);
font-weight: 500;
font-size: 1.1em;
}
input:focus {
box-shadow: 0 0 0 0.25rem var(--input-shadow-color);
}
input::placeholder {
color: var(--input-placeholder-color);
font-weight: 500;
opacity: 0.7;
}
button {
padding: 0.60em 1.3em;
background-color: var(--search-btn-background-color);
color: #fff;
font-weight: 500;
border: 5px solid var(--search-btn-border-color);
background-color: var(--search-btn-background-color);
border-radius: 12px;
transition: 0.5s;
}
button:hover {
color: #fff;
background-color: var(--btn-hover-color);
}
button:focus {
box-shadow: 0 0 0 0.25rem var(--search-btn-shadow-color);
}
`}</style>
</form>
);
function handleFocus() {
setPlaceholder("");
}
function handleBlur() {
setPlaceholder("أخل اسم البلد أو المنطقة...");
}
function handleInput(event) {
setInputText(event.target.value);
}
function handleSubmit(event) {
event.preventDefault();
axios
.get(
`https://api.openweathermap.org/data/2.5/weather?q=${inputText}&units=metric&appid=5a60c3e5c70d9f4ad304b2b115b3bf72&lang=ar`
)
.then((response) => {
onInput(response.data);
})
.catch((error) => {
console.log(error);
onInput(0);
});
setInputText("");
}
}
Input.propTypes = {
onInput: PropTypes.func.isRequired,
};
export default Input;

SSG in NextJS only happens for queries inside a getStaticProps function.
In you example, your query is inside the component, so no query is performed at build time, but at run time as usual, so your search feature is working as expected.

Related

Chunk loading error in production React for MacOS and IOS users

I've got a problem for few weeks and I'm not even sure of his reason.
After building with the create-react-app template and deploying the app in production for an unknown reason a CSS chunk isn't called on all MacOS, IOS navigators (there aren't any errors on the console) but on Windows and Android the chunk is called by the navigators.
However, with the versions deployed in test and dev, it works fine for every user.
I've tried many things to debug this:
Remove the LazyLoading of this component.
Include the chunk in the head of index.html.
Suppress the CSS file and paste his content into another CSS file to reduce the number of chunks.
Change the instance type where it's deployed to have the same environment as dev and test.
Here's some screenshots of the difference:
The chunk called on Windows and Android
The render on Windows and Android
The render on MacOS and IOS
Here the code of the component:
import React, { useState } from 'react';
import { Button, Modal, Form } from 'react-bootstrap';
import '../../../../styles/reusable/popIn/AddFreeModal/addFreeModal.scss';
import validator from 'validator';
import { sendInviteEmail } from '../../../../reducers/mail';
import { useDispatch } from 'react-redux';
import { useToasts } from 'react-toast-notifications';
export default function AddFreeModal(props) {
const { handleClose, show } = props;
const { addToast } = useToasts();
const [email, setEmail] = useState('');
const [first_name, setFirst] = useState('');
const [last_name, setLast] = useState('');
const [emailErr, setEmailErr] = useState('');
const [first_nameErr, setFirstErr] = useState('');
const [last_nameErr, setLastErr] = useState('');
const dispatch = useDispatch();
const verifMail = (email) => validator.isEmail(email);
const verifFirst = (first_name) => first_name.length > 2;
const verifLast = (last_name) => last_name.length > 2;
const emailNotExist = () => addToast(`Echec de l'invitation, adresse mail erronée: ${email}`, {
appearance: 'error',
autoDismiss: true,
});
const emailAlreadySend = () => addToast('Invitation déja envoyée cette semaine réessayez plus tard !', {
appearance: 'error',
autoDismiss: true,
});
const mailSend = () => handleClose('true');
const handleForm = async () => {
setEmailErr('');
setFirstErr('');
setLastErr('');
if (verifMail(email) && verifFirst(first_name) && verifLast(last_name)) {
const res = await dispatch(sendInviteEmail(email, first_name, last_name));
if (res === 'False') emailNotExist();
else if (res === 'Already Send') emailAlreadySend();
else mailSend()
setEmail('')
setFirst('')
setLast('')
} else {
if (!verifMail(email)) setEmailErr('Veuillez entrer un mail valide !');
if (!verifFirst(first_name)) setFirstErr('Veuillez entrer un prenom !');
if (!verifLast(last_name)) setLastErr('Veuillez entrer un nom !');
}
};
return (<>
<Modal size="lg" className='addFreeModal' show={show} onHide={() => {handleClose(); setFirst(''); setEmail(''), setLast(''), setEmailErr(''); }}>
<Modal.Header closeButton>
<Modal.Title>Inviter un Consultant</Modal.Title>
</Modal.Header>
<Modal.Body className='formBody'>
<Form>
<Form.Control className='form-input' onChange={(e) => setEmail(e.target.value)} type="email"
placeholder="Email" />
{emailErr && <p className='txt-danger'>{emailErr}</p>}
<Form.Control className='form-input' onChange={(e) => setFirst(e.target.value)} type="email"
placeholder="Prénom" />
{first_nameErr && <p className='txt-danger'>{first_nameErr}</p>}
<Form.Control className='form-input' onChange={(e) => setLast(e.target.value)} type="email"
placeholder="Nom" />
{last_nameErr && <p className='txt-danger'>{last_nameErr}</p>}
</Form>
</Modal.Body>
<Modal.Footer>
<Button className='cancel-btn' onClick={() => {handleClose(); setFirst(''); setEmail(''), setLast('')}}> Annuler </Button>
<Button className='send-btn' onClick={handleForm}> Envoyer </Button>
</Modal.Footer>
</Modal>
</>);
}
And his style:
$graycolor: #ecececec;
$cancelColor: #57585a;
$greenColor: #3de4cf;
$blueColor: #426DEA;
$redcolor: red;
$whitecolor: #fff;
$blackColor: #000;
.addFreeModal {
.modal-content {
border-radius: 30px;
}
.modal-lg {
max-width: 40% !important;
}
.modal-header {
justify-content: center;
padding: 1rem 1rem 0rem 1rem;
button.close {
opacity: 1;
height: 5%;
width: 5%;
border-radius: 50px;
font-family: monospace;
background-color: $blueColor !important;
&:hover {
opacity: 1;
color: white;
background-color: $blueColor !important;
}
}
.close {
color: #fff;
text-shadow: none;
font-size: 1.8rem;
padding: 1px 0px 28px 0px;
font-weight: 400;
}
.modal-title {
font-weight: 600;
font-size: 2.5em;
margin: 20px auto 0px auto;
color: $greenColor;
}
}
.form-control{
height: calc(2em + .5rem + 2px);
}
.form-input {
width: 70%;
margin: 10px 0px 0px 15%;
border: solid #d1d2d4 1px;
border-radius: 12px;
}
.txt-danger {
font-size: 15px;
text-align: center;
}
.modal-footer {
padding: 0rem 1rem 1.5rem 1rem;
.send-btn {
width: 34%;
height: calc(2em + .5rem + 2px);
border-radius: 20px;
font-weight: 600;
font-size: 1.2em;
background-color: $blueColor;
margin-bottom: 5%;
&:hover {
cursor: pointer;
}
}
.cancel-btn {
width: 34%;
height: calc(2em + .5rem + 2px);
font-weight: 600;
background-color: $graycolor !important;
border: solid $graycolor 1px;
border-radius: 20px;
font-size: 1.2em;
color: $cancelColor;
margin-bottom: 5%;
&:hover {
cursor: pointer;
}
}
}
}

Convert Class from single Js web page to ReactJs

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>
}

Delete specific item clicking icon React js

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 });
}

Redirect inside a getInitialProps with next.js and Parse Server

EDIT :
I set a cookie when the user is connected et store the token inside a cookie. And with the GetInitialPropsi access to the cookie and i check if the session is set to an user or not.
It seems it only work when i access to this page when i use a link : home page to this page for exemple but when i type the url it doesn't work.
I'm using npm install --save next-cookies for retrieve the cookie :
https://www.npmjs.com/package/next-cookies
I'm sorry it's probably a stupid question but i'm still learning ...
Here is the whole code of my page Login.js
import React, { Component, useState } from 'react'
import Parse from 'parse'
import Snackbar from '#material-ui/core/Snackbar';
import Cookies from 'js-cookie'
import cookies from 'next-cookies'
export default function login() {
const [state, setState] = React.useState({
username: "",
password: "",
}
)
const [error, setError] = useState(false)
async function handleConnection() {
try {
const user = await Parse.User.logIn(state.username, state.password)
console.log(user)
var currentUser = Parse.User.current();
const token = currentUser.getSessionToken()
//console.log(token)
Cookies.set('token', token, { expires: 365 })
setError(false)
} catch (e) {
setError(true)
}
}
function handleChange(evt) {
const value = evt.target.value;
setState({
...state,
[evt.target.name]: value
});
}
return (
<div className="notConnected container-fluid">
<div className="containerFormLogin">
<h1>Connectez-vous !</h1>
<p>{error ? "Nom d'utilisateur ou mot de passe incorrect" : ''}</p>
<label>Nom d'utilisateur ou mail</label>
<input type="text" name="username" onChange={handleChange} />
<label>Mot de passe</label>
<input type="password" name="password" onChange={handleChange} />
<button className="pulse" onClick={handleConnection}>Se connecter</button>
<p>Pas encore de compte ? Inscrivez-vous par ici !</p>
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
open={error}
autoHideDuration={3000}
message={<span id="message-id">Impossible de se connecter, vérifier vos informations de connexion</span>}
ContentProps={{
"aria-describedby": "message-id"
}}
></Snackbar>
</div>
<style jsx>{`
.notConnected
{
background-image: url('/images/notConnected.svg');
height: 100vh;
width: 100%;
background-position: center;
background-size: cover;
background-repeat: no-repeat;
display: flex,
}
p:empty
{
margin:0 !important;
}
.containerFormLogin
{
width: 400px;
background-color: rgba(255,255,255, 0.8);
box-shadow: rgba(0,0,0, 0.5) 10px 10px 10px;
border-radius: 10px;
display: flex;
flex-direction: column;
padding: 30px;
margin:auto;
transition: all .2s ease-in;
}
.containerFormLogin:hover
{
background-color: rgba(255,255,255, 1);
}
.containerFormLogin h1
{
margin-bottom: 40px;
font-family: 'Raleway', sans-serif;
font-size: 25px;
text-align: center;
}
.containerFormLogin p
{
font-size: 12px;
font-family: 'Raleway', sans-serif;
margin-top: 10px;
}
.containerFormLogin label
{
font-size: 12px;
font-family: 'Raleway', sans-serif;
}
.containerFormLogin input
{
margin-bottom: 20px;
font-family: 'Raleway', sans-serif;
font-size: 15px;
padding-top: 10px;
padding-bottom: 10px;
}
.error
{
border-color: red;
}
button
{
background: none;
border: 2px solid;
font: inherit;
line-height: 1;
padding: 1em 2em;
color: #ef6eae;
-webkit-transition: 0.25s;
transition: 0.25s;
}
button:hover, button:focus {
border-color: #ef8f6e;
color: #ef8f6e;
}
.pulse:hover,
.pulse:focus {
-webkit-animation: pulse 1s;
animation: pulse 1s;
box-shadow: 0 0 0 2em rgba(255, 255, 255, 0);
}
#-webkit-keyframes pulse {
0% {
box-shadow: 0 0 0 0 #ef8f6e;
}
}
#keyframes pulse {
0% {
box-shadow: 0 0 0 0 #ef8f6e;
}
}
`}</style>
</div >
)
}
login.getInitialProps = (ctx) => {
const allCookies = cookies(ctx).token;
const UserToken = Parse.User.me(allCookies)
if (UserToken) {
// the user is connected so we do the redirection beacause when he's connected he can't have access to this page
return (
UserToken
)
} else {
// Do something else
}
}
EDIT #2 :
When i reach the page with a link like homePage to the login page i have this error
Unhandled Rejection (TypeError): res is undefined
and when I'm reloading the page or if i access by his url he give me an other error :
ReferenceError: localStorage is not defined
Here is my getInitialProps:
connexion.getInitialProps = ({ ctx, res }) => {
const cookies = Cookies.get('tokenUserParse');
const UserToken = Parse.User.me(cookies)
if (UserToken) {
// the user is connected so we do the redirection beacause when he's connected he can't have access to this page
res.writeHead(403, {
Location: '/'
});
res.end();
} else {
// Do something else
}
}
You need to understand that the same code that you have in getInitialProps will run both in the server (Node.js environment) and in the browser (javascript). Some libraries will work well for both environments but some libraries won't. So sometimes you need to perform different actions depending on which environment the code is running in. Something like this should fix your problem:
const isServer = typeof window === 'undefined';
const Parse = isServer ? require('parse/node') : require('parse');
connexion.getInitialProps = async ({ ctx, res }) => {
const cookies = Cookies.get('tokenUserParse');
const UserToken = await Parse.User.me(cookies)
if (UserToken) {
// the user is connected so we do the redirection beacause when he's connected he can't have access to this page
if (isServer) {
res.writeHead(302, {
Location: '/'
});
res.end();
} else {
document.location.href = '/'
}
} else {
// Do something else
}
}

React.js - TODO List edit button not working

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>

Categories

Resources