I have a table in my project and I have an edit / view / add page that I can access from this table. My goal is to send the clicked data to the other component without any problem, but no matter how hard I try, I get an undefined error and the project is broken. I would be glad if you could help.
I am sharing my codes from parent to child component
Table page.
import React, { useState, useEffect, useCallback, useMemo } from "react";
import ManagementTable from '../components/ManagementTable'
import {
getApps,
updateStopRisk,
countLiveCountry,
updateAppShow,
deleteApp,
} from "../api/apiCalls";
import VisibilityIcon from "#material-ui/icons/Visibility";
import DeleteIcon from "#material-ui/icons/Delete";
import EditIcon from "#material-ui/icons/Edit";
import Switch from "#material-ui/core/Switch";
import DeleteModal from "../components/DeleteModal";
import { Link } from "react-router-dom";
const Management = () => {
const [apps, setApps] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [currentApp, setCurrentApp] = useState("");
const [appID, setAppID] = useState(0);
const fetchData = useCallback(async () => {
const { data: appsResponse } = await getApps();
const countLiveCountries = await fetchLiveCountriesForApps(appsResponse);
setApps(
appsResponse.map((app, idx) => ({
...app,
countLiveCountry: countLiveCountries[idx],
}))
);
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const fetchLiveCountriesForApps = async (appwLive) => {
const countLiveCountries = await Promise.all(
appwLive.map((app) => countLiveCountry(app.appID))
);
return countLiveCountries.map(({ data: liveCountries }) => liveCountries);
};
const removeApp = async () => {
await deleteApp(appID);
setModalVisible(false);
fetchData();
};
const onClickCancel = () => {
setModalVisible(false);
};
const columns = useMemo(() => [
{
Header: "Application Name",
accessor: "app_name",
},
{
Header: "Business Area",
accessor: "businessarea.businessarea_name",
},
{
Header: "Live Plants",
accessor: "countLiveCountry",
},
{
Header: "Line Stop Risk",
accessor: "app_stoprisk",
Cell: ({ row: { original } }) => {
const changeCheck = async (id) => {
await updateStopRisk(id);
fetchData();
};
return (
<input
checked={original.app_stoprisk}
onClick={() => {
changeCheck(original.appID);
}}
id="appStopRisk"
type="checkbox"
style={{ width: 18, height: 18, marginTop: 5 }}
/>
)
},
sortType: (a, b, id) => {
if (a.original[id] > b.original[id]) return -1;
if (b.original[id] > a.original[id]) return 1;
},
},
{
Header: "Actions",
Cell: ({ row: { original } }) => {
const changeTrack = async (id) => {
await updateAppShow(id);
fetchData();
};
return (
<>
<Link
className="btn btn-manage-link btn-sm col-2"
to={{
pathname: `/management/${original.app_name}`,
mode: "view",
id: original.appID
}}
>
<VisibilityIcon></VisibilityIcon>
</Link>
<Link
to={{
pathname: `/management/${original.app_name}`,
mode: "edit",
id: original.appID
}}
className="btn btn-manage-link btn-sm col-2"
>
<EditIcon></EditIcon>
</Link>
<button
onClick={() => {
setModalVisible(true);
setCurrentApp(original.app_name);
setAppID(original.appID);
}}
className="btn btn-manage-link btn-sm col-3"
>
<DeleteIcon></DeleteIcon>
</button>
<Switch
onClick={() => changeTrack(original.appID)}
checked={original.app_show}
className="col-3"
></Switch>
</>
)
},
},
],
[fetchData]
);
return (
<div className="container">
<h2 style={{ float: "left", font: "bold" }}>Management</h2>
<div style={{ float: "right" }}>
<Link className="btn btn-danger btn-sm" to={{ pathname: `/management/add`, mode: "add" }}>
Add New App
</Link>
<Link className="btn btn-danger btn-sm ml-3" exact to="/management/plants">
Plant Management
</Link>
</div>
<ManagementTable columns={columns} data={apps} />
<DeleteModal
message={<strong>{currentApp}</strong>}
variety="app"
onClickCancel={onClickCancel}
onClickOk={removeApp}
visible={modalVisible}
/>
</div>
);
};
export default Management;
The page where I transfer the props.
import React, { useState, useEffect } from "react";
import Accordion from "../components/Accordion";
import Details from '../components/Details'
import {
getByIdApps,
} from "../api/apiCalls";
const ApplicationManagement = (props) => {
const [appById, setAppById] = useState([]);
const { id } = props.location;
const [selectOption, setSelectOption] = useState('add')
useEffect(() => {
getData();
getMode();
}, [])
const getData = async () => {
console.log(props.location.id)
if (props.location.id) {
await getByIdApps(props.location.id).then((response) => setAppById(response.data))
console.log(appById)
console.log(props)
}
else {
setSelectOption('add')
}
}
const getMode = () => props.location.mode ? setSelectOption(props.location.mode) : setSelectOption('add')
const handleOptionChange = (event) => {
console.log(event.target.value)
setSelectOption(event.target.value)
}
return (
<>
<div style={{ margin: 20 }}>
<h1>
{appById.app_shortcode} - {appById.app_fullname}
</h1>
<div className="float-right mb-auto">
<label><input type="radio" value="view" checked={selectOption === 'view'} onChange={handleOptionChange} />View</label>
<label> <input type="radio" value="add" checked={selectOption === 'add'} onChange={handleOptionChange} />Add</label>
<label> <input type="radio" value="edit" checked={selectOption === 'edit'} onChange={handleOptionChange} />Edit</label>
</div>
<br></br>
<div style={{ marginLeft: 50, marginRight: 50 }} >
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Links</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Factory Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Issues Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Middleware Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
</div>)
{selectOption === 'add' ? (
<div>
Add Mode
</div>
) : selectOption === 'view' ? (<div>View Mode</div>) : (<div>eidt</div>)}
</div>
</>
);
};
export default ApplicationManagement;
and the section where the details are kept on the ApplicationManagement page (My code is quite long, I just share the problem part.)
import React, { useState, useEffect } from 'react'
import axios from "axios";
import {
getResponsibleTeams,
getBusinessAreas
} from '../api/apiCalls'
const Details = (props) => {
const [rTeams, setrTeams] = useState([]);
const [bAreas, setbAreas] = useState([]);
const { data } = props;
useEffect(() => {
async function fetchData() {
const getrTeams = await getResponsibleTeams();
const getbAreas = await getBusinessAreas();
axios.all([getrTeams, getbAreas]).then(
axios.spread((...allData) => {
const allrTeams = allData[0].data;
const allbAreas = allData[1].data;
setrTeams(allrTeams);
setbAreas(allbAreas);
})
);
}
fetchData();
}, []);
return (
<div>
<div
style={{
float: "left",
width: 1350,
height: 340,
}}
>
<div className="form-group">
<label style={{ float: "left" }} htmlFor="appFullName">
Frontend:{" "}
</label>
<input
id="appFullName"
type="text"
class="form-control"
placeholder="dsfdsdsf"
value={data.frontend.frontend_name} // error here
//onChange={handleInputChange}
name="appShortCode"
style={{ width: 400, marginLeft: 150 }}
/>
</div>
</div>
</div>
)
}
export default Details;
Later I realized that using asynchronous functions caused some problems. I came up with a solution to this and the problem was solved.
Error Code Here :
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
and the solution to the problem
{appById &&
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>}
Related
I am visualising a List of Cards with content and what I want to achieve is to set contentEditable=true to the clicked card via its button. I am able to select the content of the element, however contentEditable is not set to true and it returns the following error instead:
Uncaught TypeError: Cannot create property 'contentEditable' on string
And I cant figure out why. What am I doing wrong here and how can I set contentEditable to true for the clicked element via its button?
Here is my code:
import * as React from 'react';
import { ListView } from '#progress/kendo-react-listview';
import { Input } from '#progress/kendo-react-inputs';
import {
Card,
CardTitle,
CardImage,
CardActions,
CardBody,
} from '#progress/kendo-react-layout';
import { Pager } from '#progress/kendo-react-data-tools';
import articles from '../data/articles.json';
import { BubbleChart } from "../components/products/BubbleChart"
const onEdit = (item) => {
console.log(item.Content)
let cardContent = item.Content.contentEditable = "true";
return cardContent
}
const MyItemRender = (props) => {
let item = props.dataItem;
return (
<div
style={{
padding: '20px 20px',
}}
className="parent-container"
>
<div className="k-card-list">
<Card
style={{
width: 260,
height: 340
}}
>
<CardBody
style={{
borderBottom: 'solid 1px rgba(0,0,0,.08)'
}}
>
<CardImage
src={require(`../assets/article-images/${item.Image}`)}
style={{
width: 260,
height: 140,
maxWidth: 260,
}}
/>
<CardTitle
style={{
fontSize: 18,
}}
/>
<CardTitle>{item.Title}</CardTitle>
<CardTitle>{item.Subtitle}</CardTitle>
<p className="content">
Some quick example text to build on the card title and make up the
bulk of the card content.
</p>
</CardBody>
<CardActions>
<div className="footer-buttons-container">
<span>
<span className="k-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-base">
<span className="k-icon k-i-preview"></span>Review
</span>
</span>
<span>
<span className="k-button k-edit-button k-button-md k-button-rectangle k-rounded-md k-button-flat k-button-flat-primary" onClick={() => onEdit(item)}>
<span className="k-icon k-i-edit"></span>Edit
</span>
</span>
</div>
</CardActions>
</Card>
</div>
</div>
);
};
export const Products = () => {
const [filteredList, setFilteredList] = React.useState(articles);
const [value, setValue] = React.useState('');
const [page, setPage] = React.useState({
skip: 0,
take: 10,
});
const handlePageChange = (e) => {
setPage({
skip: e.skip,
take: e.take,
});
};
const handleChange = React.useCallback((event) => {
setValue(event.target.value);
const results = articles.filter(post => {
if (event.target.value === "") return articles
return post.Title.includes(event.target.value)
})
console.log(results)
setFilteredList(results)
});
const { skip, take } = page;
return <div>
<div className="chart-container">
<br/>
<br/>
<BubbleChart/>
</div>
<div className="input-container">
<Input
style={{
border: '2px solid #ccc',
boxShadow: 'inset 0px 0px 0.5px 0px rgba(0,0,0,0.0.1)',
}}
placeholder={'Search'}
value={value}
onChange={handleChange}
/>
</div>
<div className="listbox-card-container">
<ListView
data={filteredList.slice(skip, skip + take)}
item={MyItemRender}
style={{
width: '100%',
height: '100%',
}}
/>
<Pager
skip={skip}
take={take}
onPageChange={handlePageChange}
total={articles.length}
/>
</div>
</div>
}
Can't do multiple assigning in one line. add separate lines
const onEdit = (item) => {
console.log(item.Content)
const content = {...item.Content }
content.contentEditable = "true";
return content
}
I have a scenario where I have 2 different components ( buttons and an info container). On each button click I am trying to display each matched info container. I am able to achieve the desired functionality in my buttons, but when I pass state back to my other component I am only able to display the matched index. My desired result is if I clicked a button in my nav and it has an active class all my "info container" should remain visible until the "active" class is toggled/removed.
JS:
...
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
"& > *": {
margin: theme.spacing(1)
}
},
orange: {
color: theme.palette.getContrastText(deepOrange[500]),
backgroundColor: deepOrange[500],
border: "4px solid black"
},
info: {
margin: "10px"
},
wrapper: {
display: "flex"
},
contentWrapper: {
display: "flex",
flexDirection: "column"
},
elWrapper: {
opacity: 0,
"&.active": {
opacity: 1
}
}
}));
const ToggleItem = ({ onChange, id, styles, discription }) => {
const [toggleThisButton, setToggleThisButton] = useState(false);
const handleClick = (index) => {
setToggleThisButton((prev) => !prev);
onChange(index);
};
return (
<>
<Avatar
className={toggleThisButton ? styles.orange : ""}
onClick={() => handleClick(id)}
>
{id}
</Avatar>
{JSON.stringify(toggleThisButton)}
{/* {toggleThisButton && <div className={styles.info}>{discription}</div> } */}
</>
);
};
const ToggleContainer = ({ discription, className }) => {
return <div className={className}> Content {discription}</div>;
};
export default function App() {
const data = ["first", "second", "third"];
const classes = useStyles();
const [value, setValue] = useState(false);
const handleChange = (newValue) => {
setValue(newValue);
console.log("newValue===", newValue);
};
return (
<>
<div className={classes.wrapper}>
{data.map((d, id) => {
return (
<div key={id}>
<ToggleItem
id={id}
styles={classes}
discription={d}
onChange={handleChange}
/>
</div>
);
})}
</div>
<div className={classes.contentWrapper}>
{data.map((d, id) => {
return (
<ToggleContainer
className={
value === id
? clsx(classes.elWrapper, "active")
: classes.elWrapper
}
key={id}
styles={classes}
discription="Hello"
/>
);
})}
</div>
</>
);
}
Codesanbox:
https://codesandbox.io/s/pedantic-dream-vnbgym?file=/src/App.js:0-2499
Codesandbox : https://codesandbox.io/s/72166087-zu4ev7?file=/src/App.js
You can store the selected tabs in a state. That way you don't need to render 3 (or more) <ToggleContainer>. In <ToggleContainer> pass the selected tabs as props and render the selected tabs content in <ToggleContainer>.
import React, { useState } from "react";
import "./styles.css";
import { makeStyles } from "#material-ui/core/styles";
import Avatar from "#material-ui/core/Avatar";
import { deepOrange } from "#material-ui/core/colors";
import clsx from "clsx";
const useStyles = makeStyles((theme) => ({
root: {
display: "flex",
"& > *": {
margin: theme.spacing(1)
}
},
orange: {
color: theme.palette.getContrastText(deepOrange[500]),
backgroundColor: deepOrange[500],
border: "4px solid black"
},
info: {
margin: "10px"
},
wrapper: {
display: "flex"
},
contentWrapper: {
display: "flex",
flexDirection: "column"
},
elWrapper: {
opacity: 0,
"&.active": {
opacity: 1
}
}
}));
const ToggleItem = ({ onChange, id, styles, discription }) => {
const [toggleThisButton, setToggleThisButton] = useState(false);
const handleClick = (index) => {
onChange(discription, !toggleThisButton);
setToggleThisButton((prev) => !prev);
};
return (
<>
<Avatar
className={toggleThisButton ? styles.orange : ""}
onClick={() => handleClick(id)}
>
{id}
</Avatar>
{JSON.stringify(toggleThisButton)}
{/* {toggleThisButton && <div className={styles.info}>{discription}</div> } */}
</>
);
};
const ToggleContainer = ({ className, selected }) => {
return (
<div className={className}>
{selected.map((item, idx) => (
<div key={idx}>Content {item}</div>
))}
</div>
);
};
export default function App() {
const data = ["first", "second", "third"];
const classes = useStyles();
const [selected, setSelected] = useState([]);
// action : False -> Remove, True -> Add
const handleChange = (val, action) => {
let newVal = [];
if (action) {
// If toggle on, add content in selected state
newVal = [...selected, val];
} else {
// If toggle off, then remove content from selected state
newVal = selected.filter((v) => v !== val);
}
console.log(newVal);
setSelected(newVal);
};
return (
<>
<div className={classes.wrapper}>
{data.map((d, id) => {
return (
<div key={id}>
<ToggleItem
id={id}
styles={classes}
discription={d}
onChange={handleChange}
/>
</div>
);
})}
</div>
<div className={classes.contentWrapper}>
<ToggleContainer styles={classes} selected={selected} />
</div>
</>
);
}
I just made a shopping card with redux toolkit and reactJs. but I do not know how to handle the repetition of products in my shopping card. and It just add the same product several times!
how can I handle this?
shoppingCard.js
import { createSlice } from "#reduxjs/toolkit";
import { createSelector } from "reselect";
// Create Slice
const slice = createSlice({
name: "shoppingCard",
initialState: { shoppingCardList: [], loading: true },
reducers: {
addItemToCart: (state, action) => {
const pseudoId = new Date().getTime(); //generating id for cart items
state.shoppingCardList.push({
id: pseudoId,
productName: action.payload.product.name,
productId: action.payload.product.product_code,
quantity: action.payload.Quantity,
price: parseInt(action.payload.product.price),
totalPrice:
action.payload.Quantity * parseInt(action.payload.product.forosh),
});
state.loading = false;
},
removeItemFromCart: (state, action) => {
state.shoppingCardList = state.shoppingCardList.filter(
(cartItem) => cartItem.id !== action.payload.cartItemId
);
},
},
});
// console.log(slice);
// selectors
export const getShoppingCartItem = (state) => state.cart.shoppingCardList;
export const getTotalPrice = (state) => {
return state.cart.shoppingCardList.reduce((total, shoppingCardList) => {
return shoppingCardList.totalPrice + total;
}, 0);
};
export const { addItemToCart, removeItemFromCart } = slice.actions;
export default slice.reducer;
shoppingCard.jsx
import React from "react";
import CardItem from "./shoppingCardItem";
import { useSelector } from "react-redux";
import { addCommas } from "#persian-tools/persian-tools";
import { Link } from "react-router-dom";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faArrowLeft } from "#fortawesome/free-solid-svg-icons";
import { Card } from "react-bootstrap";
import {
getCartState,
getShoppingCartItem,
getTotalPrice,
} from "../store/shoppingcard";
import "../css/shoppingCard.css";
import Loader from "react-loader-spinner";
const ShoppingCard = () => {
const cartItem = useSelector(getShoppingCartItem);
const total = useSelector(getTotalPrice);
console.log("state shoppingCart", cartItem);
return (
<React.Fragment>
<Card className="fixed-top">
<Card.Body>
<Link to="/nav/products">
<FontAwesomeIcon icon={faArrowLeft} style={{ float: "left" }} />
</Link>
</Card.Body>
</Card>
<Loader
style={{
position: "fixed",
top: "50%",
left: "50%",
transform: "translate(-50%, -50%)",
zIndex: "10",
}}
visible={state.loading === true ? true : false}
type="Puff"
color="#00BFFF"
height={100}
width={100}
/>
<div style={{ height: "95vh", overflow: "scroll" }}>
<CardItem cartItem={cartItem} />
</div>
<Card className="fixed-bottom">
<Card.Body>
<div className="row">
<div style={{ textAlign: "center" }} className="col-6">
مجموع : {addCommas(total)} ریال
</div>
<div style={{ textAlign: "center" }} className="col-6">
<button className="btn btn-primary">ارسال سفارش</button>
</div>
</div>
</Card.Body>
</Card>
</React.Fragment>
);
};
export default ShoppingCard;
and the file of the shoppingCardItem is this.
shoppingCardItem.jsx
import React from "react";
import Icon from "./icon";
import { Card } from "react-bootstrap";
import { addCommas } from "#persian-tools/persian-tools";
import { useDispatch } from "react-redux";
import { removeItemFromCart } from "../store/shoppingcard";
const CardItem = ({ cartItem }) => {
const dispatch = useDispatch();
return (
<React.Fragment>
{cartItem.map((cartItem) => (
<Card className="shoppingCard" key={cartItem.productId}>
<Card.Header>نام کالا : {cartItem.productName}</Card.Header>
<Card.Body>
<div className="row" style={{ margin: "auto" }}>
<div className="col-8">
<div className="row secondary">
قیمت پایه : {addCommas(cartItem.price)} ریال
</div>
<div className="row">
تعداد کارتن سفارش شده :{cartItem.quantity}
</div>
<div className="row secondary">
مجموع : {addCommas(cartItem.totalPrice)} ریال
</div>
</div>
<div className="col-4">
<img src="" alt="picture of products" />
</div>
</div>
<div className="row m-2" style={{ float: "left" }}>
<button style={{ width: "auto" }} className="btn btn-success m-2">
+
</button>
<button style={{ width: "auto" }} className="btn btn-warning m-2">
-
</button>
<button
style={{ width: "auto" }}
className="btn btn-danger m-2"
onClick={() =>
dispatch(removeItemFromCart({ cartItemId: cartItem.id }))
}
>
<Icon />
</button>
</div>
</Card.Body>
</Card>
))}
</React.Fragment>
);
};
export default CardItem;
these are my redux and reactjs shopping card files.
I want to check if a product is already exist then just update the quantity number not adding another product with the same data.
Please check the below code I have added the logic in the shoppingCard.js component.
You can set your extra logic if you want.
addItemToCart: (state, action) => {
const pseudoId = new Date().getTime(); //generating id for cart items
//Add logic for update the existing cart items start
const existingCartItemIndex = state.shoppingCardList.findIndex(
(item) => item.productId === action.item.productId
);
const existingCartItem = store.shoppingCardList[existingCartItemIndex];
let updatedItems;
if (existingCartItem) {
//Find the index and update the items
const updateItem = {
...existingCartItem,
//extra code - add your logic
quantity: existingCartItem.quantity + action.payload.quantity,
}
updatedItems = [...state.shoppingCardList]
updatedItems[existingCartItemIndex] = updateItem;
} else {
const addObject = {
id: pseudoId,
productName: action.payload.product.name,
productId: action.payload.product.product_code,
quantity: action.payload.Quantity,
price: parseInt(action.payload.product.price),
totalPrice:
action.payload.Quantity * parseInt(action.payload.product.forosh),
};
//state.shoppingCardList.push(addObject);
updatedItems = state.shoppingCardList.concat(addObject);
}
//Add logic for update the existing cart items end
state.loading = false;
}
How can I get the clicked card only to change its string from 'not captured' to 'captured'? Right now, all cards' strings say 'captured' even if I click on only one. I think the problem is that the captured state updates for all the cards and I can't get the captured state to update for the single clicked card. It's an onChange event and a checkbox.
import React, { useState, useEffect } from 'react'
import PokemonCard from '../components/PokemonCard';
const Pokedex = () => {
const [pokemons, setPokemons] = useState([]);
const [captured, setCaptured] = useState(false )
const URL = 'https://pokeapi.co/api/v2/pokemon/?limit=151';
const fetchingPokemons = async () => {
const res = await fetch(URL);
const data = await res.json();
// console.log(data)
setPokemons(data.results)
}
useEffect(() => {
fetchingPokemons()
}, [URL])
const toggleCaptured= (e, id) => {
console.log(id)
if(id && e) {
console.log('oh')
setCaptured(captured => !captured)
}
let capturedPkm = [];
let notCapturedPkm = [];
pokemons.forEach(i => {
if(captured === true) {
capturedPkm.push(pokemons[i])
} else {
notCapturedPkm.push(pokemons[i])
}
})
console.log('captured', capturedPkm, 'not captured', notCapturedPkm)
}
return (
<>
<div style={{display: 'flex', flexWrap: 'wrap', justifyContent: 'space-evenly'}}>
{pokemons ? pokemons.map((pokemon) => {
return (
<>
<div style={{ width: '235px' }} >
<PokemonCard
pokemon={pokemon}
name={pokemon.name}
url={pokemon.url}
key={pokemon.id}
captured={captured}
toggleCaptured={toggleCaptured}
/>
</div>
</>
)
}) : <h1>Loading...</h1>}
</div>
</>
)
}
export default Pokedex
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import PokemonIcon from './PokemonIcon';
const PokemonCard = (props) => {
const { url, captured, toggleCaptured } = props
const URL = url
const [pokemonCard, setPokemonCard] = useState([])
const fetchingPokemonCard = async () => {
const res = await fetch(URL);
const data = await res.json();
//console.log(data)
setPokemonCard(data)
}
useEffect(() => {
fetchingPokemonCard()
}, [URL])
return (
<>
<div className='pokemon-card' style={{
height: '250px',
maxWidth: '250px',
margin: '1rem',
boxShadow: '5px 5px 5px 4px rgba(0, 0, 0, 0.3)',
cursor: 'pointer',
}} >
<Link
to={{ pathname: `/pokemon/${pokemonCard.id}` }}
state={{ pokemon: pokemonCard, captured }}
style={{ textDecoration: 'none', color: '#000000' }}>
<div
style={{ padding: '20px', display: 'flex', justifyContent: 'center', alignItems: 'center' }} >
<PokemonIcon img={pokemonCard.sprites?.['front_default']} />
</div>
</Link>
<div style={{ textAlign: 'center' }}>
<h1 >{pokemonCard.name}</h1>
<label >
<input
type='checkbox'
defaultChecked= {captured}
onChange={(e) => toggleCaptured(e.target.checked, pokemonCard.id)}
/>
<span style={{ marginLeft: 8, cursor: 'pointer' }}>
{captured === false ? 'Not captured!' : 'Captured!'}
{console.log(captured)}
</span>
</label>
</div>
</div>
<div>
</div>
</>
)
}
export default PokemonCard
Use an object as state:
const [captured, setCaptured] = useState({})
Set the toggle function:
const toggleCaptured = (checked, id) => {
const currentChecked = { ...captured }; // Create a shallow copy
console.log(id)
if (checked) {
currentChecked[id] = true;
} else {
delete currentChecked[id];
}
setCaptured(currentChecked); // Update the state
let capturedPkm = pokemons.filter(({id}) => currentChecked[id]);
let notCapturedPkm = pokemons.filter(({id}) => !currentChecked[id]);
console.log('captured', capturedPkm, 'not captured', notCapturedPkm)
}
The PokemonCard should look like this
<PokemonCard
pokemon={pokemon}
name={pokemon.name}
url={pokemon.url}
key={pokemon.id}
captured={captured[pokemon.id]} // Here
toggleCaptured={toggleCaptured}
/>
I have a NotificationStepper Component which gets inputs from user, I need to update this input value in run time in another component named TabComponent. Both of the components are child components of SendNotification Component. How can i achieve that in reactjs.
EDIT
NotificationStepper.js
const styles = {
transparentBar: {
backgroundColor: 'transparent !important',
boxShadow: 'none',
paddingTop: '25px',
color: '#FFFFFF'
}
};
const useStyles = makeStyles((theme: Theme) =>
createStyles({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}),
);
function getSteps() {
return ['Create', 'Audience', 'Timing'];
}
function getStepContent(step, $this) {
switch (step) {
case 0:
return (
<div className="row">
<CardBox styleName="col-lg-12"
heading="">
<form className="row" noValidate autoComplete="off" style={{"flex-wrap":"no-wrap", "flex-direction": "column" }}>
<div className="col-md-12 col-12">
<TextField
id="campaign_name"
label="Campaign Name"
value={$this.state.name}
onChange={$this.handleChange('name')}
margin="normal"
fullWidth
/>
</div>
</form>
</CardBox>
</div>
);
default:
return 'Unknown step';
}
}
class NotificationStepper extends React.Component {
state = {
activeStep: 0,
name: '',
};
handleChange = name => event => {
this.setState({
[name]: event.target.value,
});
};
handleNext = () => {
this.setState({
activeStep: this.state.activeStep + 1,
});
};
handleBack = () => {
this.setState({
activeStep: this.state.activeStep - 1,
});
};
handleReset = () => {
this.setState({
activeStep: 0,
});
};
render() {
const steps = getSteps();
const {activeStep} = this.state;
return (
<div className="col-xl-12 col-lg-12 col-md-7 col-12">
<Stepper className="MuiPaper-root-custom" activeStep={activeStep} orientation="vertical">
{steps.map((label, index) => {
return (
<Step key={label}>
<StepLabel>{label}</StepLabel>
<StepContent className="pb-3">
<Typography>{getStepContent(index, this)}</Typography>
<div className="mt-2">
<div>
<Button
disabled={activeStep === 0}
onClick={this.handleBack}
className="jr-btn"
>
Back
</Button>
<Button
variant="contained"
color="primary"
onClick={this.handleNext}
className="jr-btn"
>
{activeStep === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
</div>
</div>
</StepContent>
</Step>
);
})}
</Stepper>
{activeStep === steps.length && (
<Paper square elevation={0} className="p-2">
<Typography>All steps completed - you"re finished</Typography>
<Button onClick={this.handleReset} className="jr-btn">
Reset
</Button>
</Paper>
)}
</div>
);
}
}
export default NotificationStepper;
TabComponent.js
TabContainer.propTypes = {
children: PropTypes.node.isRequired,
dir: PropTypes.string.isRequired,
};
class TabComponent extends Component {
state = {
value: 0,
};
render() {
const {theme} = this.props;
return (
<div className="col-xl-12 col-lg-12 col-md-12 col-12" style={{"margin-top": "15px"}}>
<NotifCard key={0} data={{'name': 'Title of Notification', 'company': 'sayge.ai', 'image': require("assets/images/chrome.png"), 'description': 'Notification Message here'}} styleName="card shadow "/>
</div>
);
}
}
TabComponent.propTypes = {
theme: PropTypes.object.isRequired,
};
export default withStyles(null, {withTheme: true})(TabComponent);
and this is my SendNotification.js
const SendNotification = ({match}) => {
return (
<div className="dashboard animated slideInUpTiny animation-duration-3">
<ContainerHeader match={match} title={<IntlMessages id="sidebar.notification"/>}/>
<div className="row" style={{'flex-wrap': 'no wrap', "flex-direction": 'row'}}>
<div className="col-xl-7 col-lg-7 col-md-7 col-7">
<NotificationStepper/>
<div className='flex-class' style={{'width': '100%'}}>
<Button color="primary" style={{"align-self": "flex-end", "border" : "1px solid", "margin-left": "10px", "margin-bottom": "40px"}} size="small" className="col-md-2 col-2">Fetch</Button>
<Button color="primary" style={{"align-self": "flex-end", "border" : "1px solid", "margin-left": "10px", "margin-bottom": "40px"}} size="small" className="col-md-2 col-2" color="primary">Discard</Button>
</div>
</div>
<div className="col-xl-5 col-lg-5 col-md-5 col-5" style={{"padding-top": "20px"}}>
<span style={{"margin-left" : "20px", "font-weight": "bold"}}>Preview</span>
<TabComponent />
</div>
</div>
</div>
);
};
export default SendNotification;
i need to get the name value from NotificationStepper and Update it in pass it to in TabComponent.
There are plenty of tutorials about that. For instance, this.
import React, { Component, createRef } from "react";
class CustomTextInput extends Component {
textInput = createRef();
focusTextInput = () => this.textInput.current.focus();
render() {
return (
<>
<input type="text" ref={this.textInput} />
<button onClick={this.focusTextInput}>Focus the text input</button>
</>
);
}
}
import React, { useRef } from "react";
const CustomTextInput = () => {
const textInput = useRef();
focusTextInput = () => textInput.current.focus();
return (
<>
<input type="text" ref={textInput} />
<button onClick={focusTextInput}>Focus the text input</button>
</>
);
}