I tried to make an input checkbox when I click the input checkbox, it should be displayed a check image like this.
However, it didn't show the checkbox and I am not sure how to check that the input box was checked or not. Could you help me with what part do I missed and where is something wrong?
I really appreciate your help!
This is CSS inputl and label part
.colors {
display: flex;
flex-direction: column;
span {
margin-bottom: 20px;
}
.colorLists {
margin-left: 10px;
display: flex;
flex-wrap: wrap;
.colorLayout {
display: flex;
flex-direction: column;
position: relative;
width: 33%;
height: 80px;
flex-shrink: 0;
align-items: center;
justify-content: center;
.checkboxLabel {
background-color: beige;
border: 1px solid #ccc;
border-radius: 50%;
cursor: pointer;
height: 28px;
left: 0;
position: absolute;
top: 40;
width: 28px;
&:after {
border: 2px solid #fff;
border-top: none;
border-right: none;
content: '';
height: 6px;
left: 7px;
opacity: 0;
position: absolute;
top: 8px;
transform: rotate(-45deg);
width: 12px;
// opacity: 0.2;
}
}
input[type='checkbox'] {
visibility: hidden;
}
input[type='checkbox']:checked {
& + label {
background-color: beige;
border-color: beige;
&:after {
opacity: 1;
}
}
}
.productColor {
margin-top: 70px;
font-size: 13px;
margin-right: 21px;
}
}
}
}
.sizes {
.HorizontalLine {
margin-top: 25px;
}
.span {
}
.sizeLists {
margin-top: 20px;
margin-bottom: 20px;
button {
margin: 5px;
width: 44px;
height: 32px;
background-color: white;
border: 1px solid silver;
border-radius: 15%;
}
}
}
This is js part
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input type="checkbox" />
<label
className="checkboxLabel"
for="checkbox"
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
In react you have to set the htmlFor property for the label instead of for.
The value should be the same as the id from the input.
Then you can add a value property for the input which is used for adding/removing the item in the list of selected items.
For this purpose a handleChange function can be defined.
const [selectedItems, setSelectedItems] = useState([]);
function handleChange(e) {
let newSelected = [];
if (selectedItems.includes(e.target.value)) {
newSelected = selectedItems.filter((item) => item !== e.target.value);
} else {
newSelected = [...selectedItems, e.target.value];
}
setSelectedItems(newSelected);
}
return (
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input
onChange={handleChange}
type="checkbox"
id={idx}
value={color.color_name}
checked={selectedItems.includes(color.color_name)}
/>
<label
className="checkboxLabel"
htmlFor={idx}
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
);
EDIT: Since you are using a class component it can be rewrittenlike this:
export default class CheckboxListComponent extends Component {
constructor(props) {
super(props);
this.state = { selectedItems: [] };
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let newSelected = [];
if (this.state.selectedItems.includes(e.target.value)) {
newSelected = this.state.selectedItems.filter(
(item) => item !== e.target.value
);
} else {
newSelected = [...this.state.selectedItems, e.target.value];
}
this.setState({ selectedItems: newSelected });
}
render() {
return (
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input
onChange={this.handleChange}
type="checkbox"
id={idx}
value={color.color_name}
checked={this.state.selectedItems.includes(color.color_name)}
/>
<label
className="checkboxLabel"
htmlFor={idx}
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
);
}
}
You must tell react that your input is checked so that your CSS will apply it. selected ids must be kept in a place for future existence check. in the following code, I named this array selecetedIdx.
You also need to add idx on selection(via onChange event handler) or wrap them all in form and add them via extra dom attribute.
class Main extends Component {
// initialize selectedIdx with [] in your state (esp constructor)
// e.g. this.state = {/* rest of state, */ selectedIdx: []}
render() {
return (
{COLOR_LISTS.map((color, idx) => {
return (
// ...
<input
type="checkbox"
checked={selectedIdx.includes(idx)}
onChange={() => this.setState(state => ({
selectedIdx: [...state.selectedIdx, idx]
}))}
/>
// ...
)}
)
}
Your checkbox element needs name and value properties and would normally be a child of the <form> element.
Related
On click on the Text Area, button should add relevant text area in a pag. By clicking on the close button, system should remove the added textarea in a React page. By default, the close button shouldn't display. In this example, system is adding the text area, but once it is removed, I am not able to add the textarea anymore. Could someone please advise the issue here.
CSB link:
https://codesandbox.io/s/nervous-currying-jojdhi?file=/src/App.js
import "./styles.css";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
export default function App() {
const [multiInput, setMultiInput] = useState("");
const [createCode, setCreateCode] = useState("");
const [createImageTag, setImageTag] = useState("");
const [visible, setVisible] = useState(true);
const createCodeSection = () => {
const newElement = React.createElement("blockquote", {
contenteditable: "true",
className: "codehighlight",
name: "codesection" + new Date().getTime()
});
setCreateCode((createCode) => [...createCode, newElement]);
};
const createMultilineTextSection = () => {
const newElement = React.createElement("textarea", {
contenteditable: "true",
className: "defaultTextArea",
name: "textarea" + new Date().getTime()
});
setCreateCode((multiInput) => [...multiInput, newElement]);
};
const createImageSection = () => {
const newElement = React.createElement("img", {
key: "ele" + new Date().getTime()
});
setCreateCode((createImageTag) => [...createImageTag, newElement]);
};
const removeElement = () => {
setVisible((prev) => !prev);
};
return (
<div id="App">
<div className="adminSection">
<div className="row">
<div className="logout"></div>
<div className="createBlogSection">
<div className="row">
<button onClick={createMultilineTextSection}>Text Area</button>
<button onClick={createCodeSection}>Code</button>
<button>Image</button>
</div>{" "}
<br></br>
<div className="row">
<textarea className="defaultTextArea"></textarea>
</div>
<br></br>
<div className="row">
{visible && <span className="dtextArea">{createCode}</span>}
</div>
<div className="row">
{visible && (
<div>
<span className="closeElement">
<button onClick={removeElement}>X</button>
</span>
<span>{multiInput}</span>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
}
//css
.App {
font-family: sans-serif;
text-align: center;
}
.adminSection {
width: 100%;
}
.adminSection h1 {
margin: 25px 0px 0px 550px !important;
color: black !important;
}
.logout img {
height: 30px;
width: 30px;
margin: -100px 50px 0px 0px;
float: right;
}
.createBlogSection {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(700px, 1fr));
grid-gap: 25px !important;
margin: 100px 20px 10px 20px !important;
/* border: solid 1px; */
border-color: #e2e8f0;
border-radius: 0px 5px 5px 0px !important;
background-color: #fff;
}
.defaultTextArea {
height: 100px;
width: 300px;
margin: 10px 0px 10px 40px;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
background-color: #fff !important;
}
.codehighlight {
width: 100%;
color: #fff;
display: flex;
-webkit-flex-direction: column;
-ms-flex-direction: column;
flex-direction: column;
background-color: #353232 !important;
}
.closeElement {
margin-left: 320px;
display: none;
}
Instead of how you've put the added elements, use:
const removeElement = (index) => {
const newElements = multiInput.filter((_, i) => i == index);
setMultiInput(newElements);
};
// Inside "return" (createBlogSection div)
multiInput.map((_input, index) => {
<div key={index}>
{_input}
<span className="closeElement">
<button onClick={removeElement(index)}>X</button>
</span>
</div>
})
Edit:
Add const [multiInput, setMultiInput] = useState([]); and instead of pushing new elements into separate variables add all into multiInput only. Using setMultiInput(multiInput) => [...multiInput, newElement]); in each case.
I am trying to build on the beginner react tutorial.
The below code compiles successfully in terminal. Note, only the lines from "Square" downwards are directly relevant, I think.
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
const size = 30
class DropDown extends React.Component{
algorithm_states = {
alg:0,
}
algClick(i){
this.algorithm_states.alg = i;
}
startResetClick(i){
switch(i){
default:
case 0:
//enable disable buttons on grid
//run relevent processes bases on algorithm state machine
break;
case 1:
// clear grid and matrix
// enable buttons on grid
break;
}
}
render(){
return(
<header>
<button className = "main">
Main
</button>
<div className="dropdown">
<span>Choose Rule</span>
<div className="dropdown-content">
{/* algorithms mapped to their indicies in list */}
<button
onClick={() => this.algClick(0)}
>Game Of Life</button>
<button
onClick={() => this.algClick(1)}
>Langtons Ant</button>
</div>
</div>
{/* start button mapped to 0, reset button mapped to 1 */}
<button
className = "start"
onClick={() => this.startResetClick(0)}
>START</button>
<button
className = "stop"
onClick={() => this.startResetClick(1)}
>RESET</button>
</header>
)
}
}
class Square extends React.Component {
keys = {
x:null,
y:null,
}
render() {
return (
<button className="square" key = {this.keys.x + this.keys.y}>
</button>
);
}
}
class Board extends React.Component{
renderSquare(x, y) {
return (
<Square
keys = {[x,y]}/>
);
}
render(){
const rows = [], cols = [];
for(var i = 0; i < size; i++){
rows[i] = i;
cols[i] = i;
}
return(
<div>
{[...rows].map((x) => {
return (
<div className="board-row" key={x}>
{[...cols].map((y) => this.renderSquare(x,y))}
</div>
)
})
}
</div>
)
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<header className = "header">
<DropDown/>
</header>
<body>
<div className="game-board">
<Board />
</div>
</body>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
index.css
body {
font: 14px "Century Gothic", Futura, sans-serif;
margin: 20px;
}
ol, ul {
padding-left: 30px;
}
.header{
background: "black";
}
.main {
position: absolute;
left: 5%
}
.game-board{
position: absolute;
top: 20%;
left:30%;
}
.board-row:after {
clear: both;
content: "";
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 10px;
font-weight: bold;
line-height: 15px;
height: 15px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 15px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
.dropdown {
position: absolute;
top: 20%;
left: 5%;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
padding: 12px 16px;
z-index: 1;
}
.dropdown:hover .dropdown-content {
display: block;
}
.start{
position: absolute;
right: 15%;
}
.stop{
position: absolute;
right: 5%;
}
But in browser, I get the error
Warning: Each child in a list should have a unique "key" prop.
Check the render method of `Board`. See https://reactjs.org/link/warning-keys for more information.
Square#http://localhost:3000/static/js/main.chunk.js:249:5
Board#http://localhost:3000/static/js/main.chunk.js:268:1
div
body
div
Game#http://localhost:3000/static/js/main.chunk.js:308:1
And I'm not sure what it's about, since I'm pretty sure all the keys I have provided are unique.
Anyone got any ideas???
Cheers
K
You need to render each Square component with a key at the map level:
render(){
const rows = [], cols = [];
for(var i = 0; i < size; i++){
rows[i] = i;
cols[i] = i;
}
return(
<div>
{[...rows].map((x) => {
return (
<div className="board-row">
{[...cols].map((y) => (
<Square keys={[x,y]} key={`x-y`} />
))}
</div>
)
})
}
</div>
)
}
}
See the reference on the docs
I'm trying to create this sliding sign in /sign up portal but the original code was on Vanilla JS. The components seems unmounted on the Dom and the program is unable to find the Classlist by its id.I did few attempts on using Component did mount but it is throwing error, later I've found out that I am lacking understanding about Class vs function on react. componentDidMount() seems to be only for Classes. Now I cant seem to find a valid solution for this. Also I might forget, when should I really need to use Classes vs functions in rendering a component? How can I prevent calling an unmounted element in the DOM if I use function instead of class?
This is the raw Html,css,vanilla js code for the portal.
const signUpButton = document.getElementById('signUp');
const signInButton = document.getElementById('signIn');
const container = document.getElementById('container');
signUpButton.addEventListener('click', () => {
container.classList.add("right-panel-active");
});
signInButton.addEventListener('click', () => {
container.classList.remove("right-panel-active");
});
#import url('https://fonts.googleapis.com/css?family=Montserrat:400,800');
* {
box-sizing: border-box;
}
body {
background: #f6f5f7;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
font-family: 'Montserrat', sans-serif;
height: 100vh;
margin: -20px 0 50px;
}
h1 {
font-weight: bold;
margin: 0;
}
h2 {
text-align: center;
}
p {
font-size: 14px;
font-weight: 100;
line-height: 20px;
letter-spacing: 0.5px;
margin: 20px 0 30px;
}
span {
font-size: 12px;
}
a {
color: #333;
font-size: 14px;
text-decoration: none;
margin: 15px 0;
}
button {
border-radius: 20px;
border: 1px solid #FF4B2B;
background-color: #FF4B2B;
color: #FFFFFF;
font-size: 12px;
font-weight: bold;
padding: 12px 45px;
letter-spacing: 1px;
text-transform: uppercase;
transition: transform 80ms ease-in;
}
button:active {
transform: scale(0.95);
}
button:focus {
outline: none;
}
button.ghost {
background-color: transparent;
border-color: #FFFFFF;
}
form {
background-color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 0 50px;
height: 100%;
text-align: center;
}
input {
background-color: #eee;
border: none;
padding: 12px 15px;
margin: 8px 0;
width: 100%;
}
.container {
background-color: #fff;
border-radius: 10px;
box-shadow: 0 14px 28px rgba(0,0,0,0.25),
0 10px 10px rgba(0,0,0,0.22);
position: relative;
overflow: hidden;
width: 768px;
max-width: 100%;
min-height: 480px;
}
.form-container {
position: absolute;
top: 0;
height: 100%;
transition: all 0.6s ease-in-out;
}
.sign-in-container {
left: 0;
width: 50%;
z-index: 2;
}
.container.right-panel-active .sign-in-container {
transform: translateX(100%);
}
.sign-up-container {
left: 0;
width: 50%;
opacity: 0;
z-index: 1;
}
.container.right-panel-active .sign-up-container {
transform: translateX(100%);
opacity: 1;
z-index: 5;
animation: show 0.6s;
}
#keyframes show {
0%, 49.99% {
opacity: 0;
z-index: 1;
}
50%, 100% {
opacity: 1;
z-index: 5;
}
}
.overlay-container {
position: absolute;
top: 0;
left: 50%;
width: 50%;
height: 100%;
overflow: hidden;
transition: transform 0.6s ease-in-out;
z-index: 100;
}
.container.right-panel-active .overlay-container{
transform: translateX(-100%);
}
.overlay {
background: #FF416C;
background: -webkit-linear-gradient(to right, #FF4B2B, #FF416C);
background: linear-gradient(to right, #FF4B2B, #FF416C);
background-repeat: no-repeat;
background-size: cover;
background-position: 0 0;
color: #FFFFFF;
position: relative;
left: -100%;
height: 100%;
width: 200%;
transform: translateX(0);
transition: transform 0.6s ease-in-out;
}
.container.right-panel-active .overlay {
transform: translateX(50%);
}
.overlay-panel {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 0 40px;
text-align: center;
top: 0;
height: 100%;
width: 50%;
transform: translateX(0);
transition: transform 0.6s ease-in-out;
}
.overlay-left {
transform: translateX(-20%);
}
.container.right-panel-active .overlay-left {
transform: translateX(0);
}
.overlay-right {
right: 0;
transform: translateX(0);
}
.container.right-panel-active .overlay-right {
transform: translateX(20%);
}
.social-container {
margin: 20px 0;
}
.social-container a {
border: 1px solid #DDDDDD;
border-radius: 50%;
display: inline-flex;
justify-content: center;
align-items: center;
margin: 0 5px;
height: 40px;
width: 40px;
}
footer {
background-color: #222;
color: #fff;
font-size: 14px;
bottom: 0;
position: fixed;
left: 0;
right: 0;
text-align: center;
z-index: 999;
}
footer p {
margin: 10px 0;
}
footer i {
color: red;
}
footer a {
color: #3c97bf;
text-decoration: none;
}
<div class="container" id="container">
<div class="form-container sign-up-container">
<form action="#">
<h1>Create Account</h1>
<div class="social-container">
<i class="fab fa-facebook-f"></i>
<i class="fab fa-google-plus-g"></i>
<i class="fab fa-linkedin-in"></i>
</div>
<span>or use your email for registration</span>
<input type="text" placeholder="Name" />
<input type="email" placeholder="Email" />
<input type="password" placeholder="Password" />
<button>Sign Up</button>
</form>
</div>
<div class="form-container sign-in-container">
<form action="#">
<h1>Sign in</h1>
<div class="social-container">
<i class="fab fa-facebook-f"></i>
<i class="fab fa-google-plus-g"></i>
<i class="fab fa-linkedin-in"></i>
</div>
<span>or use your account</span>
<input type="email" placeholder="Email" />
<input type="password" placeholder="Password" />
Forgot your password?
<button>Sign In</button>
</form>
</div>
<div class="overlay-container">
<div class="overlay">
<div class="overlay-panel overlay-left">
<h1>Welcome Back!</h1>
<p>To keep connected with us please login with your personal info</p>
<button class="ghost" id="signIn">Sign In</button>
</div>
<div class="overlay-panel overlay-right">
<h1>Hello, Friend!</h1>
<p>Enter your personal details and start journey with us</p>
<button class="ghost" id="signUp">Sign Up</button>
</div>
</div>
</div>
</div>
And this is my current Login.js for my portal on a function.
import React, { useState } from 'react';
import axios from 'axios';
import { setUserSession } from './Utils/Common';
import './Login.css';
function Login(props) {
const [loading, setLoading] = useState(false);
const username = useFormInput('');
const password = useFormInput('');
const [error, setError] = useState(null);
const handleLogin = () => {
setError(null);
setLoading(true);
axios.post('http://localhost:4000/users/signin', { username: username.value, password: password.value }).then(response => {
console.log(username, password);
setLoading(false);
setUserSession(response.data.token, response.data.user);
props.history.push('/dashboard');
}).catch(error => {
setLoading(false);
if (error.response.status === 401) setError(error.response.data.message);
else setError("Something went wrong. Please try again later.");
});
}
const Signup = () => {
setError(null);
setLoading(true);
props.history.push('/Signup');
}
return (
<div className='login-wrapper' >
<div className='user-wrapper'>
<h1>Library Management System</h1>
<br />
<h1>Login</h1>
<br /><br />
<div className="user-details">
<h3>Username</h3>
<img src={userlogo} className="login-logo-user" />
<input type="text" {...username} autoComplete="new-password" />
</div>
<div className="user-details">
<h3>Password</h3>
<img src={passwordlogo} className="login-logo-password"/>
<input type="password" {...password} autoComplete="new-password" />
</div>
{error && <><small style={{ color: 'red' }}>{error}</small><br /></>}<br />
<input type="button" value={loading ? 'Loading...' : 'Login'} onClick={handleLogin} disabled={loading} id='buttons'/>
<input type="button" value={loading ? 'Loading...' : 'Signup'} onClick={Signup} id='buttons'/>
<div className="forgot-password">
<h5>Forgot Password? Click <span id="forgot-password">here</span>.</h5>
</div>
</div>
<div className='logo-wrapper'>
<div className="logo-main">
<img src={librarylogo} id="mainlogo"/>
<h2>Library Management System v1.0</h2>
</div>
</div>
</div>
);
}
const useFormInput = initialValue => {
const [value, setValue] = useState(initialValue);
const handleChange = e => {
setValue(e.target.value);
}
return {
value,
onChange: handleChange
}
}
export default Login;
Is this correct by the way?
I am trying to convert this as well?
from this function.
function login(props) {
const [loading, setLoading] = useState(false);
const username = useFormInput('');
const password = useFormInput('');
const [error, setError] = useState(null);
}
into a class:
class Login extends React.Component{
constructor(props) {
super(props);
this.state = {
loading, setLoading : false,
username : useFormInput(''),
password : useFormInput(''),
error, setError = null
}
}
}
I got it working now. Thanks for all the help.
class Login extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
setLoading: false,
email: props.email,
password: props.password,
error: null,
setError: null
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount(){
const signUpButton = document.getElementById('signUp');
const signInButton = document.getElementById('signIn');
const container = document.getElementById('container');
if (container){
console.log('loaded');
signUpButton.addEventListener('click', () => {
container.classList.add("right-panel-active");
});
signInButton.addEventListener('click', () => {
container.classList.remove("right-panel-active");
});
}
}
handleChange(event) {
this.setState({
[event.target.type]: event.target.value
});
}
handleSubmitSignIn(event) {
// alert('A name was submitted: ' + this.state.email + this.state.password);
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
}
handleSubmitSignUp(event) {
// alert('A name was submitted: ' + this.state.email + this.state.password);
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
}
render() {
return (
<div className="container" id="container">
<div className="form-container sign-up-container">
<form onSubmit={this.handleSubmitSignUp}>
<h1>Create Account</h1>
<div className="social-container">
<i className="fab fa-facebook-f"></i>
<i className="fab fa-google-plus-g"></i>
<i className="fab fa-linkedin-in"></i>
</div>
<span>or use your email for registration</span>
<input type="text" placeholder="Name" autoComplete="new-name" />
<input type="email" placeholder="Email" autoComplete="new-email" />
<input type="password" placeholder="Password" autoComplete="new-password" />
<input type="department" placeholder="Department" autoComplete="new-name" />
<input type="year" placeholder="Year" autoComplete="new-email" />
<input type="schoolId" placeholder="School Id No." autoComplete="new-password" />
<button>Sign Up</button>
</form>
</div>
<div className="form-container sign-in-container">
<form onSubmit={this.handleSubmitSignIn}>
<h1>Sign in</h1>
<div className="social-container">
<i className="fab fa-facebook-f"></i>
<i className="fab fa-google-plus-g"></i>
<i className="fab fa-linkedin-in"></i>
</div>
<span>or use your account</span>
<input type="email" placeholder="Email" value={this.state.email} autoComplete='new-email' onChange={this.handleChange}/>
<input type="password" placeholder="Password" value={this.state.password} autoComplete='new-password' onChange={this.handleChange}/>
Forgot your password?
<button type='submit' >Sign In</button>
</form>
</div>
<div className="overlay-container">
<div className="overlay">
<div className="overlay-panel overlay-left">
<h1>Welcome Back!</h1>
<p>To keep connected with us please login with your personal info</p>
<button className="ghost" id="signIn">Sign In</button>
</div>
<div className="overlay-panel overlay-right">
<h1>Hello</h1>
<p>Enter your personal details and start journey with us</p>
<button className="ghost" id="signUp">Sign Up</button>
</div>
</div>
</div>
</div>
);
}
}
export default Login;
I'm building a multiple chatbox messaging like Facebook's popup messenger windows. At the moment, the user can call up a chatbox, close it, minimize it, etc.
When I click on multiple users, say 3, I'm supposed to have three chatboxes pop up corresponding to those three different users. Currently, only one chatbox appears.
This screenshot illustrates what I want to achieve. On each user's button click, it's own chatbox will popup.
Here is the demo and download link for a jQuery equivalent: link.
This is the full React code which shows just one chat box:
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import axios from 'axios';
import './style.css';
class MessageBox extends Component {
constructor() {
super();
this.state = {
showBox: false,
shownToggle: true,
data: [
{ id: "1", name: "Tony" },
{ id: "2", name: "Mark" },
{ id: "3", name: "Joy" }
],
currentRec: undefined,
};
this.showBox = this.showBox.bind(this);
this.closeBox = this.closeBox.bind(this);
this.toggle = this.toggle.bind(this);
}
showBox = (i, pid, name) => {
this.setState({ currentRec: i });
console.log(`Selected record index: ${i}`);
alert(pid);
alert(name);
this.setState({ showBox: true }, () => {
document.addEventListener('click', this.closeBox);
});
}
closeBox(event) {
if (this.dropdownBox.contains(event.target)) {
this.setState({ showBox: false }, () => {
document.removeEventListener('click', this.closeBox);
});
}
}
toggle() {
this.setState({
shownToggle: !this.state.shownToggle
});
}
render() {
var hidden = {
display: this.state.shownToggle ? "block" : "none"
}
return (
<div>
<ul style={{ float: "right" }}>
{this.state.data.map((person, i) => (
<div className="chat-sidebar" key={i}>
<button onClick={() => this.showBox(i, person.id, person.name)}>Chat with {person.name}</button>
{this.state.showBox ? (
<div className="msg_box" style={{ right: '270px' }}>
<div onClick={this.toggle.bind(this)} class="msg_head">
(<b style={{ color: 'orange' }}>
{this.state.currentRec !== undefined &&
<div className="modal-body">
{this.state.data[this.state.currentRec].name}
({this.state.data[this.state.currentRec].id})
</div>
}
</b>)
Minimize
<div className="close" ref={(element) => { this.dropdownBox = element; }} style={{ color: 'white' }}>Close</div>
</div>
<div style={hidden} className="msg_wrap"><div className="msg_body">Message will appear here</div></div>
</div>) : (null)}
</div>
))}
</ul>
</div>
);
}
}
/****** Chat Popup Layout ******/
body{
background: #e5e5e5;
font-family: sans-serif;
}
.msg_box{
position: fixed;
bottom: -5px;
width: 250px;
background: white;
border-radius: 5px 5px 0px 0px;
}
.msg_head{
background: black;
color: white;
padding: 8px;
font-weight: bold;
cursor: pointer;
border-radius: 5px 5px 0px 0px;
}
.msg_body{
background: white;
height: 200px;
font-size: 12px;
padding: 15px;
overflow: auto;
overflow-x: hidden;
}
.close{
float: right;
cursor: pointer;
}
.minimize{
float: right;
cursor: pointer;
padding-right: 5px;
}
/****** Slider Layout Popup ******/
.chat-sidebar {
width: 250px;
height: 100%;
right: 0px;
top: 0px;
padding-top: 10px;
padding-bottom: 10px;
border: 1px solid #b2b2b2;
}
After series of efforts, the use of jquery and Reactjs is what solved my issue as per code below
const dataSet = this.state.data;
alert(dataSet);
if ($.inArray(pid, dataSet) != -1)
{
dataSet.splice($.inArray(pid, this.state.data), 1);
}
dataSet.unshift(pid);
var s = 270 ; // start position
var j = 260; //next position
$.each(dataSet, function( index, value ) {
if(index < 4){
$('[rel="'+value+'"]').css("right",s);
$('[rel="'+value+'"]').show();
s = s+j;
}
else{
$('[rel="'+value+'"]').hide();
}
I'm rather new to whole react thing, going through courses on FCC. My problem come from CSS/SCSS itself. I tried ordinary CSS and SCSS. My page is done in React. The page is also hosted on codepen. All three versions are the same, codepen, git and local and yet CSS is somewhat different between them. My previous projects who are also hosted on these platforms and in local have also the same CSS but they look identical. Difference between local and codepen's version isn't that drastic, but between local>codepen>github is more than noticeable as you descend. Do GitHub ignores/renders? or what, React differently? This question should also apply to codepen.
My codepen
My git page
My repoToProject
Image of localhost:
html from codepen:
<div id="root"></div>
scss from codepen:
$position: absolute;
$percentage: 100%;
$color: whitesmoke;
$car: auto;
#import url("//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css");
.btn1 {
position: $position;
bottom: -30px;
left: 51.3%;
z-index: 999;
background-color: $color;
border: 1px solid gray;
color: aqua;
}
#root {
width: $percentage;
}
body,
html {
height: $percentage;
}
body {
background-color: $color;
background-image: url("../images/react1.png");
background-repeat: no-repeat;
background-size: $car;
background-position: center bottom;
overflow: hidden;
}
.grid-container {
display: grid;
grid-template-columns: 50% 50%;
background-color: $color;
padding: 10px;
grid-gap: 15px;
width: $percentage;
grid-template-rows: 30px 25px 98%;
}
.grid-item {
text-align: center;
}
#inner2 {
padding-left: 20px;
padding-right: 25px;
border-bottom: 15px solid #d6e9c6;
padding-bottom: 55px;
background-color: #fcf8e3;
width: $percentage;
margin-left: $car;
margin-right: $car;
position: $position;
top: 0px;
left: 0px;
height: $percentage;
min-height: 20%;
max-height: $percentage;
}
#editor {
width: $percentage;
background-color: white;
resize: none;
color: #495057;
border: 1px solid #ced4da;
border-radius: 0.25rem;
overflow-y: $car;
max-height: $percentage;
min-height: 40px;
margin-bottom: 40px;
}
#preview {
width: 98.9%;
background-color: white;
border-radius: 0.25rem;
border: 1px solid #ced4da;
overflow-y: $car;
max-height: $percentage;
min-height: 40px;
margin-bottom: 40px;
}
#item1,
#item2 {
font-family: "Russo One";
font-style: oblique;
font-weight: bold;
font-size: 2em;
margin-bottom: 10px;
padding-bottom: 0px;
width: $percentage;
background-color: #fcf8e3;
min-height: 50px;
border-bottom: none;
padding-top: 10px;
}
.insignia {
letter-spacing: 5px;
-webkit-transition: letter-spacing 1s;
transition: letter-spacing 1s;
}
.insignia:hover {
letter-spacing: 13px;
cursor: pointer;
}
.ui-resizable-s {
cursor: row-resize;
}
textarea:focus,
input:focus {
outline: none;
}
#arrow {
background-color: #dff0d8;
width: $percentage;
height: 15px;
position: $position;
bottom: -12px;
padding-left: 0px;
padding-right: 0px;
font-size: 1.5em;
border-bottom: 1px solid #d6e9c6;
text-align: center;
}
.glyphicon {
top: -4px;
left: 4px;
color: gray;
-ms-transform: scale(1, 0.6); /* IE 9 */
-webkit-transform: scale(1, 0.6); /* Safari */
transform: scale(1, 0.6);
}
#media screen and (max-height: 600px) {
#inner2 {
height: 90vh !important;
}
}
#eraser {
text-align: center;
grid-column: 1 / 3;
z-index: 2;
line-height: 10px;
margin-left: $car;
margin-right: $car;
}
/*Additional styling*/
td,
th {
border: 2px solid #224b4b;
padding-left: 5px;
padding-right: 5px;
}
.label {
position: $position;
top: -10px;
left: 0px;
min-width: $percentage;
z-index: 999;
}
.preview-editor {
position: fixed;
top: 55px;
left: 0px;
min-width: $percentage;
height: $percentage;
z-index: 999;
}
h1 {
border-bottom: 2px solid #224b4b;
}
h2 {
border-bottom: 1px solid #224b4b;
}
code {
background-color: #d6e9c6;
color: #e83e8c !important;
}
blockquote {
border-left: 2px solid black;
padding-left: 5px;
margin-left: 25px;
}
#media only screen and (max-width: 768px) {
img {
width: 100%;
}
#ggED {
text-align: left;
}
#ggPrev {
text-align: right;
}
.insignia,
.insignia:hover {
letter-spacing: 0px;
font-size: 1em;
}
}
js from codepen:
var renderer = new marked.Renderer();
renderer.link = function(href, title, text) {
return (
'<a target="_blank" href="' +
href +
'" title="' +
title +
'">' +
text +
"</a>"
);
};
marked.setOptions({
breaks: true,
renderer: renderer,
sanitize: true
});
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
markdown: defaultMarkdown,
erase: false,
goFull: false,
headViewKlasa: "grid-item",
headEdKlasa: "grid-item",
editorKlasa: "",
previewKlasa: "",
stilPreview: {},
stilEditor: {},
attr: "Click on me for fullscreen",
inner2H: "",
h2Inner: false
};
this.handleChange = this.handleChange.bind(this);
this.eraseFields = this.eraseFields.bind(this);
this.inner2Height = this.inner2Height.bind(this);
}
eraseFields() {
this.setState({
erase: true
});
if (this.state.erase === false) {
this.setState({
markdown: ""
});
}
if (this.state.erase === true) {
this.setState({
markdown: defaultMarkdown,
erase: !this.state.erase
});
}
}
componentDidMount() {
this.node = ReactDOM.findDOMNode(this);
$(this.node).resizable({
handles: "s",
minHeight: 170
});
document
.querySelector(".ui-resizable-handle.ui-resizable-s")
.setAttribute(
"title",
"Double click on me or pull me down to full height"
);
}
inner2Height() {
if (this.state.h2Inner === false) {
this.setState({
inner2H: "100%",
h2Inner: true
});
}
if (this.state.h2Inner === true) {
this.setState({
inner2H: "",
h2Inner: false
});
}
}
fullScreen(clicked_id) {
if (clicked_id === "ggEd" && this.state.goFull === false) {
this.setState({
headEdKlasa: this.state.headEdKlasa + " label",
attr: "Click again to go back!",
editorKlasa: "preview-editor",
stilPreview: { display: "none" },
stilEditor: { paddingTop: "0px" },
goFull: true
});
}
if (clicked_id === "ggEd" && this.state.goFull === true) {
this.setState({
headEdKlasa: this.state.headEdKlasa.substr(0, 9),
attr: "Click on me for fullscreen",
editorKlasa: "",
stilPreview: { display: "block" },
stilEditor: { paddingTop: "10px" },
goFull: !this.state.goFull
});
}
if (clicked_id === "ggPrev" && this.state.goFull === false) {
this.setState({
headViewKlasa: this.state.headViewKlasa + " label",
attr: "Click again to go back!",
previewKlasa: "preview-editor",
stilEditor: { display: "none" },
stilPreview: { paddingTop: "0px" },
goFull: true
});
}
if (clicked_id === "ggPrev" && this.state.goFull === true) {
this.setState({
headViewKlasa: this.state.headViewKlasa.substr(0, 9),
attr: "Click on me for fullscreen",
previewKlasa: "",
stilEditor: { display: "block" },
stilPreview: { paddingTop: "10px" },
goFull: !this.state.goFull
});
}
}
handleChange(event) {
this.setState({
markdown: event.target.value
});
}
render() {
const btnText = this.state.erase ? "Populate" : "Erase";
const handleClick = e => this.fullScreen(e.target.id);
return (
<div
id="inner2"
className="grid-container animated zoomIn"
style={{ height: this.state.inner2H }}
onDoubleClick={this.inner2Height}
>
<EditorHead
id={"item1"}
style={this.state.stilEditor}
className={this.state.headEdKlasa}
onClick={handleClick}
title={this.state.attr}
/>
<PreviewHead
id={"item2"}
style={this.state.stilPreview}
className={this.state.headViewKlasa}
onClick={handleClick}
title={this.state.attr}
/>
<BtnEraser
id={"eraser"}
onClick={this.eraseFields}
type={"button"}
className={"btn btn-danger btn-lg"}
title={"Erase & populate both fields"}
value={btnText}
/>
<Editor
id={"editor"}
onChange={this.handleChange}
className={this.state.editorKlasa}
value={this.state.markdown}
placeholder={"Enter ... some kind a text!? ..."}
title={
"This is rather obvious isn't it? It's editor window Sherlock :D"
}
/>
<Preview
id={"preview"}
className={this.state.previewKlasa}
dangerouslySetInnerHTML={{
__html: marked(this.state.markdown, { renderer: renderer })
}}
title={"It's a preview window, Sherlock ;)"}
/>
<Arrow id={"arrow"} />
</div>
);
}
}
/*class Inner2 extends React.Component{
render(){
return (
<div id={this.props.id} className={this.props.className} style={this.props.style} onDoubleClick={this.props.onDoubleClick}>Editor:</div>
);
}
}*/
class EditorHead extends React.Component {
render() {
return (
<h1
id={this.props.id}
style={this.props.style}
className={this.props.className}
onClick={this.props.onClick}
>
<span className="insignia" title={this.props.title} id="ggEd">
Editor:
</span>
</h1>
);
}
}
class PreviewHead extends React.Component {
render() {
return (
<h1
id={this.props.id}
style={this.props.style}
className={this.props.className}
onClick={this.props.onClick}
>
<span className="insignia" title={this.props.title} id="ggPrev">
Previewer:
</span>
</h1>
);
}
}
class BtnEraser extends React.Component {
render() {
return (
<button
id={this.props.id}
onClick={this.props.onClick}
type={this.props.type}
className={this.props.className}
title={this.props.title}
>
{this.props.value}
</button>
);
}
}
class Editor extends React.Component {
render() {
return (
<textarea
id={this.props.id}
onChange={this.props.onChange}
className={this.props.className}
value={this.props.value}
placeholder={this.props.placeholder}
title={this.props.title}
/>
);
}
}
class Preview extends React.Component {
render() {
return (
<div
id={this.props.id}
className={this.props.className}
dangerouslySetInnerHTML={this.props.dangerouslySetInnerHTML}
title={this.props.title}
/>
);
}
}
class Arrow extends React.Component {
render() {
return (
<div id={this.props.id}>
<Glyph className={"glyphicon glyphicon-align-justify"} />
</div>
);
}
}
class Glyph extends React.Component {
render() {
return <span className={this.props.className} />;
}
}
ReactDOM.render(<DisplayMessages />, document.getElementById("root"));