I have a some popup block or modal window as you like. And I want that it will close after I press on button. Button will be visible after checkboox will be true. Help me pls. May be I have to add something to css, or JS code is incorrect.
Code is below.
class ModalWindow extends React.Component {
constructor() {
super();
this.state = {
open: false,
checked: false
};
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
this.setState({
checked: !this.state.checked
})
}
hide() {
this.setState({
open: false,
});
}
show() {
this.setState({
open: true,
});
}
componentDidMount() {
this.show();
}
render() {
const buttonContent = this.state.checked ? <div className={s.showButton}>
<button onClick={() => this.hide()} className={s.closeBtn}>Confirm yes yes</button>
</div> : null;
return (
<div className={this.state.open ? 'show':'hide'}>
<div className={s.modal}>
<h2 className={s.modalText}>Some text in block</h2>
<label>I want to confirm</label>
<input type="checkbox" checked={this.state.checked} onChange={this.handleChange}/>
{buttonContent}
</div>
</div>
);
}
}
export default withStyles(s)(ModalWindow);
.modal {
background:#fff;
width: 350px;
height: 200px;
margin: 5% auto;
padding: 5px 20px;
position: relative;
border: 2px solid #0000ee;
}
.hide {
display:none
}
.modalText {
font-size: 18px;
color: #000000;
}
label {
margin:0 15px 0 0;
}
.closeBtn {
display: block;
position: absolute;
bottom: 5px;
width: 150px;
height:50px;
margin:0 0 0 100px;
outline: none;
color: #555;
border: none;
background: #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
With react you have another way to do hiding and showing of elements. You just render it or you don't.
So instead of setting the state inside the modal dialog to show or hide the modal dialog you should have a property outside of it which decides if this dialog is rendered. Your React App should look something like this:
class ComponentWithModalDialog extends React.Component {
render() {
const {showModal} = this.props;
if(showModal) {
return <ModalWindow />
}
else {
return <div>
other content
</div>
}
}
}
Related
I am trying to write a useState() Hook, and perhaps add useEffect() to solve active state on two buttons. It is Delivery buttons that needs the first button-delivery to be active using CSS change, and if clicked on second button, PickUp, it should change CSS UI to stay active.
And yes if it is anyhow possible i want to use Hooks.
Is there any possible way to have it done on this way?
const Header = props => {
const [isActive, setIsActive] = useState(false);
function changeButtons () {
setIsActive = (!isActive)
};
return (
<Fragment>
<header className={classes.header}>
<div className={classes.logo} onClick={reload}>
<div >
Foodzilla
</div>
</div>
<div className={classes.delivery}>
<div
className={isActive ? classes.deliveryAction : classes.deliveryChoice}
onChange={changeButtons}
>Delivery</div>
<div className={classes.or}>or</div>
<div
className={isActive ? classes.pickUpAction : classes.pickUpChoice}
onChange={changeButtons}
>Pick Up</div>
</div>
Okay, so I did a mockup of what you are trying to do (I think :D). Here is a link to the working solution: https://codesandbox.io/s/quiet-mountain-68e10k?file=/src/styles.css:59-775.
The code is also below. There is definitely some refactoring that can be done, but I wanted to at least get you started on the right path.
Quick Summary:
Blue is Cicked (takes precedence over hover and default when active).
Green is Hovered (goes back to default when outside the div).
Red is Default (if not clicked or hovered, show red).
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [isDeliveryClicked, setIsDeliveryClicked] = useState(false);
const [isPickupClicked, setIsPickupClicked] = useState(false);
const [isDeliveryHovered, setIsDeliveryHovered] = useState(false);
const [isPickupHovered, setIsPickupHovered] = useState(false);
const handleClick = (e) => {
if (e.target.className.includes("delivery")) {
setIsDeliveryClicked(true);
setIsDeliveryHovered(false);
if (isDeliveryClicked === true) {
setIsDeliveryClicked(false);
setIsDeliveryHovered(true)
}
} else if (e.target.className.includes("pickup")) {
setIsPickupClicked(true);
setIsPickupHovered(false);
if (isPickupClicked === true) {
setIsPickupClicked(false);
setIsPickupHovered(true)
}
}
};
const handleOnMouseOver = (e) => {
if (e.target.className.includes("delivery")) {
setIsDeliveryHovered(true);
} else if (e.target.className.includes("pickup")) {
setIsPickupHovered(true);
}
};
const handleOnMouseLeave = (e) => {
if (e.target.className.includes("delivery")) {
setIsDeliveryHovered(false);
} else if (e.target.className.includes("pickup")) {
setIsPickupHovered(false);
}
};
const handleClassStyler = (buttonType) => {
if (buttonType === 'delivery') {
if (isDeliveryClicked === true) {
return "deliveryClicked";
} else if (isDeliveryHovered === true && isDeliveryClicked === false) {
return "deliveryHovered";
} else if (isDeliveryClicked === false && isDeliveryHovered === false) {
return "delivery";
}
} else if (buttonType === 'pickup'){
if (isPickupClicked === true) {
return "pickupClicked";
} else if (isPickupHovered === true && isPickupClicked === false) {
return "pickupHovered";
} else if (isPickupClicked === false && isPickupHovered === false) {
return "pickup";
}
}
};
return (
<div className="App">
<div
onMouseOver={handleOnMouseOver}
onMouseLeave={handleOnMouseLeave}
onClick={handleClick}
className={handleClassStyler('delivery)}
>
Delivery
</div>
<div
onMouseOver={handleOnMouseOver}
onMouseLeave={handleOnMouseLeave}
onClick={handleClick}
className={handlePickupClassStyler('pickup')}
>
Pick Up
</div>
</div>
);
}
The CSS I used for above is:
.delivery {
width: 100px;
height: 100px;
background-color: red;
border: solid black 5px;
margin: 5px;
}
.deliveryClicked {
width: 100px;
height: 100px;
background-color: blue;
border: solid black 5px;
margin: 5px;
}
.deliveryHovered {
width: 100px;
height: 100px;
background-color: green;
border: solid black 5px;
margin: 5px;
}
.pickup {
width: 100px;
height: 100px;
background-color: red;
border: solid black 5px;
margin: 5px;
}
.pickupClicked {
width: 100px;
height: 100px;
background-color: blue;
border: solid black 5px;
margin: 5px;
}
.pickupHovered {
width: 100px;
height: 100px;
background-color: green;
border: solid black 5px;
margin: 5px;
}
Well,
After reading all the input (which was incredibly helpful to get my logic straight) i have come with an idea and some refactoring:
However, as almost close to a solution i still need to solve my default state. And i am stuck again.
Default state should be Delivery, and the (button) should have active CSS as well.
Also, when i add CSS .deliveryChoice:hover {} it does not respond. My guess is that, as it is a child component the header don't respond as it reads no inside buttons.
Right now, they are both off.
My Header component:
const Header = props => {
return (
<Fragment>
<header className={classes.header}>
<div className={classes.logo} onClick={reload}>
<div >
Foodzilla
</div>
</div>
<div className={classes.delivery}>
<DeliveryButton
className={classes.deliveryChoice}
/>
</div>
<div>
<div className={classes.deliveryAdress}>
Delivery to:
</div>
</div>
<div className={classes.deliveryTime}>
<div >
Choose time: Now
</div>
</div>
<HeaderCartButton onClick={props.onShowCart} />
</header>
<div className={classes['main-image']}>
<img src={mealsImg} />
</div>
</Fragment>
And my DeliveryButton:
const deliveryChoice = [{ name: 'Delivery' }, { name: 'PickUp' }]
const DeliveryButton = () => {
const [active, setActive] = useState(false);
return deliveryChoice.map((data, k) => (
<div
key={k}
className={`deliveryChoice ${active === k ?
classes.deliveryAction : ''}`}
onClick={() => setActive(k)}
>
{data.name}
</div>
));
};
And CSS for the Button:
.deliveryChoice {
}
.deliveryAction {
background-color: #ffffff;
border-color: #ffffff;
display: flex;
font-size: 13px;
justify-content: space-around;
width: 4rem;
height: 1.8rem;
cursor: pointer;
color: rgb(0, 0, 0);
align-items: center;
border-radius: 20px;
/* padding-left: 0.5rem; */
}
I'm following this React tutorial here: https://ibaslogic.com/how-to-edit-todos-items-in-react/ to build a simple TO DO app.
I've also reviewed Why onDoubleClick event is not working in React.js? but there's no onclick event to worry about in my example.
My onDoubleClick event should call a function handleEditing but nothing happens when I double click a list item.
I'm unsure of why it does not work (the web browser does not seem to register a double click event.
Below is my example:
import React from "react";
import styles from "./TodoItem.module.css";
class TodoItem extends React.Component {
state = {
editing: false,
};
handleEditing = () => {
console.log("doubleClick")
this.setState({
editing: true,
});
};
render() {
const completedStyle = {
fontStyle: "italic",
color: "#595959",
opacity: 0.4,
textDecoration: "line-through",
};
const { completed, id, title } = this.props.todo;
let viewMode = {}
let editMode = {}
if (this.state.editing) {
viewMode.display = "none"
} else {
editMode.display = "none"
}
return (
<li className={styles.item}>
<div onDoubleClick={this.handleEditing} style={viewMode}>
<input
type="checkbox"
className={styles.checkbox}
checked={completed}
onChange={() => this.props.handleChangeProps(id)}
/>
<button onClick={() => this.props.deleteTodoProps(id)}>Delete</button>
<span style={completed ? completedStyle : null}>{title}</span>
</div>
<input type="text" style={editMode} className={styles.textInput} />
</li>
);
}
}
export default TodoItem;
I don't think this is relevant, but here is my css:
.item {
font-size: 1.2rem;
list-style-type: none;
padding: 17px 0px;
border-bottom: 1px solid #eaeaea;
}
.checkbox {
margin-right: 15px;
}
.item button {
font-size: 13px;
background: #f1f3f4;
border: none;
cursor: pointer;
float: right;
outline: none;
border-radius: 100px;
height: 50px;
width: 50px;
margin: -10px 0 0 10px;
}
.textInput {
width: 100%;
padding: 10px;
border: 1px solid #dfdfdf;
}
onDoubleClick works when your dev tool is not opened
Updated answer:
As found out in the comments, the problem was a combination of OS and Browser. Windows / Chrome in this example.
Old answer:
I haven't read into much detail, but the first difference I can spot is that in your code the handleEditing is not bound. Which should not prevent the output of your console.log. Does it appear?
onDoubleClick={this.handleEditing.bind(this)}
Hope this helps in your case.
Now I'm trying to change button style when a click event happens with react.
So I thought this was a proper way.
this.setState({
[e.target.className]:'button-hidden'
})
but it didn't work out.
I want to change button's display 'hidden' or 'none' when I click that.
How could I access this problem?
could you give me a hint?
JS Code is like that.
export default class PlanBtn extends React.Component{
state={
data:[{time:'1', value:'plug1', display:'button-hidden'},
... dummy data,]
}
removePlan=(e)=>{
console.log(e.target)
this.setState({
[e.target.className]:'button-hidden'
})
}
render(){
const list = this.state.data.map(
btn => (<button onClick={this.removePlan} className={btn.display}>{btn.value}</button>)
)
return (
<div id='plan-contain'>
<div className='plan'>
{list}
</div>
</div>
)
}
}
and css is
#plan-contain{
text-align: center;
width: 100%;
padding: 0 0.2px;
}
.plan{
width:96%;
border-radius: 3px;
margin: 1px 1px;
}
.button-hidden{
visibility: hidden;
width:9%;
}
.button-reveal{
width:9%;
padding:0.5%;
background-color: #00cc99;
color: white;
border: none;
margin: 1px 1px;
text-decoration: none;
-webkit-transition-duration: 0.4s;
transition-duration: 0.4s;
cursor: pointer;
}
.button-reveal:hover{
background-color: white;
color: #00cc99;
border: 2px solid #00cc99;
}
How could I process this?
if you help me out, I would be very happy
The display property for the specific data element in state is best to update. So, I adjusted the removePlan function to take the key of the item. It might even be worth creating a component for each data element and have the display state managed there.
Check this out -
class PlanBtn extends React.Component {
state = {
data: [{ time: "1", value: "plug1", display: "button-reveal" },
{ time: "2", value: "plug2", display: "button-reveal" }]
};
removePlan = (e, i) => {
console.log(e.target);
const dataNew = [...this.state.data];
dataNew[i].display = "button-hidden";
this.setState({
data: dataNew
});
};
render() {
console.log("here");
const list = this.state.data.map((btn, i) => (
<button onClick={e => this.removePlan(e, i)} className={btn.display}>
{btn.value}
</button>
));
return (
<div id="plan-contain">
<div className="plan">{list}</div>
</div>
);
}
}
You can try something like this.
export default class PlanBtn extends React.Component{
state={
data:[{time:'1', value:'plug1', display:'button-hidden'},
... dummy data,],
showStyle:flase
}
removePlan=(e)=>{
console.log(e.target)
this.setState({
showStyle:!this.state.showStyle
})
}
render(){
const list = this.state.data.map(
btn => (<button onClick={this.removePlan}
className={`${this.state.showStyle?'button-reveal':'button-hidden'}`}
>{btn.value}</button>)
)
return (
<div id='plan-contain'>
<div className='plan'>
{list}
</div>
</div>
)
}
I have a table like this:
When a user clicks on an Edit button, an <input> should appear in its place.
If a user clicks on another Edit button, this one will also be replaced with an <input>, and the previous <input> should disappear and show an Edit button again.
In short, only one field can be in edit mode at a time.
This is my initial state:
state = {
editnameEnable: false,
editemailEnable: false,
editaddressEnable: false,
edittelephone_noEnable: false,
}
This is my edit() method:
edit = value => {
var address_element = ['name','address','email','telephone_no'];
address_element = address_element.filter(element => element !== value);
address_element.map( val => this.setState({[`edit${val}Enable`]: false}));
this.setState({[`edit${value}Enable`]: true}, ()=>{
console.log(this.state);
});
}
This is part of the JSX inside my render method:
<td>{
this.state[`edit${this.props.item}Enable`] ? ( <input type="text"/> ) : (
<span
className="edit"
onClick={ () => this.edit(this.props.item) }>Edit</span>
)
}</td>
The issue is that when I click on an Edit button, the <input> appears, but when I click another Edit button, the previous <input> does not disappear.
What about using a single editableField property that is initially set to null?
Then, when you click on an Edit button, you set editableField to the name of that field, and inside render you check, for each field, whether editableField matches its name or not to render an Edit button or an input field.
Something like this:
class FieldCell extends React.Component {
constructor(props) {
super(props);
}
focusField = (element) => element && element.focus();
render() {
const editElement = this.props.isEditable ? (
<input type="text" ref={ this.focusField }/>
) : (
<button onClick={ () => this.props.onEdit() }>EDIT</button>
);
return (<td className="textLeft">{ editElement }</td>);
}
}
class UserData extends React.Component {
constructor(props) {
super(props);
this.state = {
editableField: null,
};
}
render() {
const editableField = this.state.editableField;
const rows = ['Name', 'Address', 'Telephone No.', 'E-Mail'].map((field) => {
const isEditable = field === editableField;
return (
<tr key={ field }>
<td>{ field }</td>
<FieldCell isEditable={ isEditable } onEdit={ () => this.setState({ editableField: field })}></FieldCell>
</tr>
);
});
return (<table>{ rows }</table>);
}
}
ReactDOM.render(<UserData />, document.getElementById('app'));
body {
font-family: monospace;
font-size: 13px;
}
table {
border: 2px solid #000;
border-collapse: collapse;
text-align: right;
width: 100%;
}
td {
border: 2px solid #000;
padding: 4px;
width: 50%;
overflow: hidden;
}
.textLeft {
text-align: left;
user-select: none;
}
button,
input {
border: 2px solid black;
padding: 4px 8px;
margin: 0;
font-family: monospace;
font-size: 13px;
box-sizing: border-box;
background: none;
outline: none;
}
button:hover,
button:focus,
input:hover,
input:focus {
border-color: blue;
color: blue;
}
button {
font-weight: bold;
}
input {
width: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
I have a custom element which takes input whenever user clicks on it I want to focus on it and create an overlay on other elements and when the user clicks outside the div I want to remove the overlay.
I am trying to do it using iron-overlay-behavior but not able to achieve the expected behavior.
<custom-element
with-backdrop
scroll-action="lock"
clicked="{{isClicked}}"
></decision-view>
All the examples shown are mostly for paper-dialog but how can I use iron-overlay-behavior for a custom element of my own?
The iron-overlay-behavior seems to be meant more for modal dialogs, what you are trying to accomplish is something different (for instance, modal dialogs are only shown one at a time, and require user input before going back to normal application/website behavior). So I think a natural thing for that behavior would be to disable anything else to focus!
When you say:
create an overlay on other elements
what does that mean? Just paint white over them like they were not visible?
I had a similar issue last week. See Showing a gray backdrop with a mixin
.
For a demo, see this pen from Makha:
<dom-module id="parent-component">
<template>
<style>
:host {
display: block;
margin: 10px auto auto auto;
border: 2px solid gray;
border-radius: 8px;
background-color: white;
padding: 5px;
width: 100px;
}
[hidden] {
display: none;
}
paper-button {
background-color: lightblue;
}
#placeholder {
width: 120px;
height: 150px;
}
</style>
<div>Try me.</div>
<paper-button on-tap="_doTap">Push</paper-button>
<div id="placeholder" hidden></div>
</template>
<script>
class ParentComponent extends Polymer.Element {
static get is() { return 'parent-component'; }
static get properties() {
return {
mychild: {
type: Object
}
}
}
_doTap(e) {
let x = (e.detail.x - 50) + 'px';
let y = (e.detail.y - 50) + 'px';
this.mychild = new MyChild();
this.mychild.addEventListener('return-event', e => this._closeChild(e));
this.$.placeholder.style.position = 'absolute';
this.$.placeholder.appendChild(this.mychild);
this.$.placeholder.style.left = x;
this.$.placeholder.style.top = y;
this.$.placeholder.removeAttribute('hidden');
this.mychild.open();
}
_closeChild(e) {
console.log('Child says '+e.detail);
this.mychild.remove();
this.mychild = null;
this.$.placeholder.setAttribute('hidden', '');
}
}
customElements.define(ParentComponent.is, ParentComponent);
</script>
</dom-module>
<parent-component></parent-component>
<dom-module id="my-child">
<template>
<style>
:host {
display: block;
margin: 10px auto auto auto;
border: 2px solid gray;
border-radius: 8px;
background-color: white;
padding: 15px;
}
paper-button {
background-color: lightgray;
}
</style>
<div>I'm a child.</div>
<paper-button on-tap="_doTap">Close</paper-button>
</template>
<script>
class MyChild extends Polymer.mixinBehaviors([Polymer.IronOverlayBehavior], Polymer.Element) {
static get is() { return 'my-child'; }
static get properties() {
return {
withBackdrop: {
type: Boolean,
value: true
}
}
}
ready() {
super.ready();
console.log("Daddy?");
}
_doTap(e) {
this.dispatchEvent(new CustomEvent('return-event',
{ detail: 'Bye!', bubbles: true, composed: true }));
}
}
customElements.define(MyChild.is, MyChild);
</script>
</dom-module>