I wrote a custom content editable component, it looks like the below
export default class TextEditor extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
}
onChange = (e) => {
let value = e.target.innerHTML;
this.props.onChange(value);
}
render() {
const { enabled , onChange , style, className, value } = this.props;
return (
<div>
<div contentEditable={enabled}
dangerouslySetInnerHTML={{ __html: value }}
ref={this.ref}
onInput={this.onChange}
style={{
...style,
height: '80px',
overflow: 'auto',
cursor: enabled ? 'text' : 'inherit',
}}
className={`form-control form-control-sm ${className}`}
placeholder="Optional Notes..."
/>
</div>
)
}
}
wherever i type something on the content editable the cursor moves to the beginning of the editable area.
it is because the this.props.onChange(value); updates the value outside and a rerender happening. How to prevent cursor reset on rerendering ??
You will need a combination of componentDidMount and shouldComponentUpdate like so:
class TextEditor extends React.Component {
constructor(props) {
super(props);
this.ref = React.createRef();
this.onChange = this.onChange.bind(this);
}
onChange(){
var html = this.ref.current.innerHTML;
if (this.props.onChange && html !== this.lastHtml) {
this.props.onChange({value: html});
}
this.lastHtml = html;
}
shouldComponentUpdate(nextProps){
return nextProps.value !== this.ref.current.innerHTML;
}
componentDidUpdate() {
if ( this.props.value !== this.ref.current.innerHTML ) {
this.ref.current.innerHTML = this.props.value;
}
}
render() {
const { enabled , style, className, value } = this.props;
return (
<div>
<div contentEditable={enabled}
dangerouslySetInnerHTML={{ __html: value }}
ref={this.ref}
onInput={this.onChange}
onBlur={this.onChange}
className="editable"
placeholder="Optional Notes..."
/>
</div>
)
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.state = {value: ""};
}
onChange({value}) {
this.setState({value})
}
render(){
return (
<TextEditor enabled={true} onChange={this.onChange} value={this.state.value}/ >
)
}
}
ReactDOM.render( <App/> , document.getElementById('app'));
.editable {
width: 100%;
height: 100px;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Related
New to React here.
I am trying to reuse a component but changing a prop passed to a child component depending on the the component is attached to.
class HowMuchDay extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>How much a {this.props.time}</p> <br />
<h4 style= {h4Style}>{this.props.theValue}</h4>
</div>
);
}
}
class Display extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
submit: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInput = this.handleInput.bind(this);
}
handleInput(event) {
this.setState({
input: event.target.value
});
}
handleSubmit(event) {
this.setState({
submit: this.state.input,
input: ""
});
event.preventDefault();
}
render() {
const formStyle = {
position: "relative",
textAlign: "center"
}
return (
<div style = {howStyle}>
<HowMuchDay theValue={this.state.submit} name={props.time}/>
<form onSubmit={this.handleSubmit} style= {formStyle}>
<input
value={this.state.input}
onChange={this.handleInput}
placeholder="how much?"
/>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
ReactDOM.render(<Display time="day"/>, document.getElementById("day"));
ReactDOM.render(<Display time="week"/>, document.getElementById("week"));
ReactDOM.render(<Display time = "month"/>, document.getElementById("month"));
Sorry for the mess. So my first thought was maybe I could pass a prop into the ReactDOM.render itself but I don't think that would work. How would I go about this?
It is recommended to use ReactDOM.render() only once (Refer this answer https://stackoverflow.com/a/62062296/13542198). I have added a component App and used Display components inside App component.
class HowMuchDay extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<p>How much a {this.props.time}</p>
<br>
<h4 style= {h4Style}>{this.props.theValue}</h4>
</div>
);
}
}
class Display extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
submit: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleInput = this.handleInput.bind(this);
}
handleInput(event) {
this.setState({
input: event.target.value
});
}
handleSubmit(event) {
this.setState({
submit: this.state.input,
input: ""
});
event.preventDefault();
}
render() {
const formStyle = {
position: "relative",
textAlign: "center"
}
return (
<div style = {howStyle} id={this.props.time}>
<HowMuchDay theValue={this.state.submit} name={props.time}/>
<form onSubmit={this.handleSubmit} style= {formStyle}>
<input
value={this.state.input}
onChange={this.handleInput}
placeholder="how much?"
/>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<>
<Display time="day" />
<Display time="week" />
<Display time="month" />
</>
);
}
}
ReactDOM.render(<App />, document.getElementById("app"));
<div id="app"></div>
I have this two elements a button and a dialog
<dialog className='w-11/12 shadow-none rounded-tl-md rounded-tr-md lg:rounded-lg absolute'>wqdwe</dialog>
<button className=" px-6 py-2 rounded absolute mt-12 ml-12" onClick={} >Click</button>
How can I open the dialog on clicking the button in React
constructor(props) {
super(props);
this.myRef = React.createRef();
}
showModals(){
this.myRef.showModal();
}
componentDidMount() {
//this.showModals()
}
EDIT: I am trying to access the .showModal() method in the dialog according to MDN https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog. How can I do that, I need the dimmed background feature when the modal is opened.
You do not need componentDidMount nor useRef with the state and using the props open of the dialog you can show it conditionally.
first solution using isOpen is the state
class Modal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<dialog style={{width: "80%", height: "80%", marginTop: 10, backgroundColor: '#eee'}}
open={this.props.open}
>
<p>Greetings, one and all!</p>
</dialog>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
isOpen: false
};
}
switchModal = (prevState) => {
this.setState((prevState, props) => {
return { isOpen: !prevState.isOpen }
});
}
render() {
return (
<div>
<button onClick={this.switchModal}>
{this.state.isOpen ? 'Close' : 'Open'} Modal
</button>
<br/>
<Modal open={this.state.isOpen}/>
</div>
);
}
}
React.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="root"></div>
second solution using native showModal method. With this method you can use the css property dialog::backdrop.
class Modal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<dialog id='modal' style={{width: "80%", height: "80%", marginTop: 10, backgroundColor: '#eee'}}
>
<p>Greetings, one and all!</p>
<button onClick={this.props.closeModal}>
Close Modal
</button>
</dialog>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
isOpen: false
};
}
switchModal = (prevState) => {
this.setState((prevState, props) => {
if(!prevState.isOpen) {
document.getElementById('modal').showModal()
} else {
document.getElementById('modal').close()
}
return { isOpen: !prevState.isOpen }
});
}
render() {
return (
<div>
{!this.state.isOpen && <button onClick={this.switchModal}>
Open Modal
</button>}
<br/>
<Modal
closeModal={this.switchModal}
/>
</div>
);
}
}
React.render(<App />, document.getElementById('root'));
dialog {
height: 80%;
width: 80%
}
dialog::backdrop {
background: rgba(255,0,0,.25);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="root"></div>
You can use the React state API to show and hide components based on actions taken elsewhere in the code.
class MyComponent extends React.Component {
constructor() {
this.state = {
isDialogVisible: false
}
}
handleClick = () => {
this.setState({ isDialogVisible: !this.state.isDialogVisible })
}
render() {
const { isDialogVisible } = this.state
return (
<div>
<Button onClick={this.handleClick}>{isDialogVisible ? 'Hide' : 'Show'} dialog</Button>
{this.state.isDialogVisible && <Dialog />}
</div>
)
}
}
I'm learning React and have managed to create a simple bankcard which has a text field and a button. The text field allows the user to type something in and it will appear on a label. This is achieved by a class component called InsertName. This component, I think I understand, receives the changeName function which is passed down from the Parent <Bankcard /> component.
Then it is 'handled' by the handleChange function in the child component <InsertName />. This then successfully copies the text from the text input field to the label.
I also have a reset button which successfully resets the label to blank.
What I want the reset button to also do is to reset the text input field as well.
I've tried creating a separate function outside of all classes to reset the text field but have no idea on how to work this.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
class Bankcard extends React.Component {
constructor(props) {
super(props);
this.changeName = this.changeName.bind(this);
this.resetButton = this.resetButton.bind(this);
this.state = {cardHolderName: ' '}
}
changeName(newName){
this.setState({cardHolderName: newName})
}
resetButton(){
this.setState({cardHolderName: ' '})
}
render() {
const cardDetails = sampleInfo[0];
return (
<div className="cssmainbox">
<InsertName onChange={this.changeName}/>
<div className="csslabel">
<label>{this.state.cardHolderName}</label>
</div>
<div className="cssbutton"></div>
<ResetButton onClick={this.resetButton}/>
<br></br>
<br></br>
<div className="cssmainnum">
{cardDetails.mainnum}
</div>
</div>
)
}
}
// resetTextField = (reset) => {
// const reset = {this.}
// }
const sampleInfo = [
{
mainnum: 123456789,
validthru: "08/19",
vsc: 1234
},
]
class InsertName extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const name = e.target.value;
this.props.onChange(name);
}
render() {
return (
<div>
<input type="text"
name="theusersname"
onChange={this.handleChange}>
</input>
</div>
)
}
}
class ResetButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
const name = e.target.value;
this.props.onClick(name);
}
render() {
return (
<div>
<button onClick={this.handleClick}/>
</div>
)
}
}
ReactDOM.render(<Bankcard />, document.getElementById('root'));
The css if you want to quickly look at it:
.cssmainbox {
width: 600px;
height: 300px;
border: 15px solid green;
padding: 40px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.cssmainnum {
font-size: 80px
}
.cssvalidthru {
font-size: 20px
}
.cssbutton {
border-radius: 5px;
What I want the reset button to also do is to reset the text input field as well.
Is there a better way to write this whole thing? I'm thinking just using functions instead of classes or because of it's interactivity is a stateful class as a parent and stateless children necessary?
Here your working code
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Bankcard extends React.Component {
constructor(props) {
super(props);
this.changeName = this.changeName.bind(this);
this.resetButton = this.resetButton.bind(this);
this.state = { cardHolderName: " " };
}
changeName(e) {
this.setState({ cardHolderName: e.target.value });
}
resetButton() {
this.setState({ cardHolderName: " " });
}
render() {
return (
<div className="cssmainbox">
<InsertName
onNameChange={this.changeName}
//you can pass the cardHolderName along with the changeName function.
cardHolderName={this.state.cardHolderName}
/>
<div className="csslabel">
<label>{this.state.cardHolderName}</label>
</div>
<div className="cssbutton" />
<ResetButton onResetClick={this.resetButton} />
</div>
);
}
}
function InsertName(props){
return (
<div>
<input
type="text"
name="theusersname"
onChange={props.onNameChange}
value={props.cardHolderName}
/>
</div>
);
}
function ResetButton(props) {
return (
<div>
<button onClick={props.onResetClick}>Reset</button>
</div>
);
}
ReactDOM.render(<Bankcard />, document.getElementById("root"));
Here is the working fiddle
Hope it will help you.
Edited
Updated InsertName & ResetButton to functional component and updated the fiddle.
I don't want to have input for Flatpickr. Instead it should be triggered by clicking from a div and then the calendar view shows up.
import React, { Component } from 'react';
import Flatpickr from 'react-flatpickr';
export default class CustomDatePicker extends Component {
constructor(props) {
super(props);
this.baseOptions = {
allowInput: false,
dateFormat: 'Z',
altInput: true,
wrap: true,
...this.props.options
};
this.state = { isOpen: false };
}
onOpenToggle = () => this.setState({ isOpen: !this.state.isOpen });
componentDidMount() {
document.addEventListener('click', this.handleClick, false);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClick, false);
}
handleClick = event => {
if (this.node && this.node.contains(event.target)) {
return;
}
this.setState({ isOpen: false });
};
render() {
const { selectedDate, label, onChange } = this.props;
const { isOpen } = this.state;
return (
<div
className="custom-date-picker"
onClick={this.onOpenToggle}
ref={node => (this.node = node)}
>
<div className="custom-date-picker-icon">
<i className="fa fa-calendar" />
</div>
<div className="custom-date-picker-select">
{selectedDate ? <div>{selectedDate}</div> : <div>{label}</div>}
</div>
<div className="custom-date-picker-arrow">
{isOpen ? (
<i className="fa fa-chevron-up" />
) : (
<i className="fa fa-chevron-down" />
)}
</div>
{isOpen && (
<div className="custom-date-picker-panel">
{/* <Flatpickr
value={selectedDate}
options={this.baseOptions}
onChange={(_, dateStr) => onChange(dateStr)}
/> */}
</div>
)}
</div>
);
}
}
Basically I need to show the calendar view inside div with className custom-date-picker-panel
and onChange I pass a function to update the able of the div
Can you please show me how to achieve that?
react-flatpickr does not have that build-in. But you can use pure flatpickr for implementing this functionality.
class App extends React.Component {
constructor(props) {
super(props);
this.datePicker = React.createRef();
}
onChange(selectedDates, dateStr, instance) {
console.log(selectedDates);
}
componentDidMount() {
flatpickr(this.datePicker.current, {
onChange: this.onChange
});
}
render() {
return(
<div style={{ border: "1px solid black", height: 100, width: 100}} ref={this.datePicker} />
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<div id="root"></div>
I have one question, how to use multiple toggle class
Please check my example below
I want to click <TaxItem /> and add some class to that element, and the second click to remove that class
import React, { Component } from "react";
import TaxItem from "./TaxItems/"
import Pentagon from "../../../assets/images/pentagon.png"
class Taxs extends Component {
constructor(props) {
super(props)
this.state = {
taxStatus: false
}
this.handleTaxStatus = this.handleTaxStatus.bind(this);
}
handleTaxStatus(element) {
console.log('sdasa', element)
}
render() {
return (
<div className="taxs">
<TaxItem
image={Pentagon}
name='Item 1'
taxStatus={false}
handleTaxStatus={this.handleTaxStatus(this)}
/>
<TaxItem
image={Pentagon}
name='Item 2'
taxStatus={false}
handleTaxStatus={this.handleTaxStatus(this)}
/>
</div>
)
}
}
export default Taxs
And here you can check button where I have onClick:
import React, { Component } from "react";
class TaxItem extends Component {
render() {
return (
<div className="tax-item" onClick={this.props.handleTaxStatus}>
<div className={this.props.taxStatus ? 'checked on' : 'checked'}><i className="icon icon-check"></i></div>
<img src={this.props.image} alt="Pentagon" />
<p>{this.props.name}</p>
</div>
)
}
}
export default TaxItem
How I can use THIS, something like jQuery.
As I said in the comment, I would suggest you to not use "THIS", which would mean use the refs, because it would lead to edit the DOM directly, which in React should be avoided when you can.
Instead, you could use an array of taxStatus property, one for each TaxItem, and using them as toggle, something like in the following:
class TaxItem extends React.Component {
localHandleClick = (_) => {
this.props.handleClick(this.props.taxStatusIndex);
};
render() {
const {taxStatus, handleClick} = this.props;
return (
<div
className={"button" + (taxStatus ? " checked" : " not-checked")}
onClick={this.localHandleClick} />
);
}
}
class Taxs extends React.Component {
constructor(props) {
super(props);
const taxItemCounter = props.num;
this.state = {
taxesStatus: new Array(taxItemCounter).fill(false)
}
}
handleClick = (i) => {
const taxesStatus = this.state.taxesStatus;
taxesStatus[i] = !taxesStatus[i];
this.setState({taxesStatus});
}
render() {
return (
<div>
{
this.state.taxesStatus.map((status, index) =>
<TaxItem
key={index}
taxStatusIndex={index}
handleClick={this.handleClick}
taxStatus={status} />
)}
</div>
);
}
}
ReactDOM.render(<Taxs num={3} />, document.getElementById('root'));
#import url(https://fonts.googleapis.com/css?family=Montserrat);
body {
font-family: 'Montserrat', sans-serif;
}
.button {
width: 100px;
height: 25px;
background: red;
margin: 10px;
cursor: pointer;
}
.button.checked {
background: green;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'></div>
Anyways, if you DO want to use "THIS" (which again, would mean using the refs), I can provide you an example.