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>
Related
I have a "Banner" object that I want to use to display my text and I made a button to toggle whether the message shows or is hidden:
function App() {
function Banner(props) {
if (!props.warn) {
return null;
}
return (
<div className="message">
{this.state.message}
</div>
);
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {showMessage: false, message: 'foo'};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState(state => ({
showMessage: !state.showMessage
}));
}
componentDidMount() {
fetch(
"https://jsonplaceholder.typicode.com/users")
.then((res) => res.json())
.then((json) => {
this.setState({
message: json,
DataisLoaded: true
});
})
}
render() {
return (
<div class="App">
<Banner warn={this.state.showMessage} />
<button onClick={this.handleToggleClick}>
{this.state.showMessage ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
return (
<div className="App">
<Page />
</div>
);
}
export default App;
Why is the text of the message variable not the text in the banner? If I replace the {this.state.message} with a string literal the banner displays it, but as the code is now when I press the button the page clears. Any ideas?
You should pass data to Banner and with useEffect and useState get and update the data when it changes
const { useEffect, useState } = React;
function Banner(props) {
const [message, setMessage] = useState('');
useEffect(() => {
setMessage(props.message);
}, [props]);
if (!props.warn) {
return null;
}
return <div className="message">{JSON.stringify(message)}</div>;
}
class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
showMessage: false,
message: 'foo',
};
this.handleToggleClick = this.handleToggleClick.bind(this);
}
handleToggleClick() {
this.setState((state) => ({
showMessage: !state.showMessage,
}));
}
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/users')
.then((res) => res.json())
.then((json) => {
this.setState({
message: json,
DataisLoaded: true,
});
});
}
render() {
return (
<div class="App">
<Banner message={this.state.message} warn={this.state.showMessage} />
<button onClick={this.handleToggleClick}>
{' '}
{this.state.showMessage ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
function App() {
return (
<div className="App">
<Page />
</div>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></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 am trying to get the following code below to display the CodeMirror onChange value when the button is clicked and then display that value inside the "output" div.
I am fairly new to react so not sure if it's best to pass the value through state or if there's an easier method.
Here is my code so far:
import React, { Component } from "react";
import { UnControlled as CodeMirror } from "react-codemirror2";
import "codemirror/mode/javascript/javascript";
import "codemirror/lib/codemirror.css";
export default class Code extends Component {
render() {
return (
<div>
<CodeMirror
value='console.log("Hello World")'
options={{
mode: "javascript",
lineNumbers: true
}}
onChange={(editor, data, value) => {
console.log(value);
}}
/>
<button onClick={}>run code</button>
<div className="Output">
<p>// Value should go here</p>
</div>
</div>
);
}
}
You can make use of state to maintain your values, and show output from your state,
class Code extends Component {
constructor(props) {
super(props)
this.state = {
runCode: false,
outputText: 'console.log("Hello World")',
}
}
runCode = () => {
this.setState({runCode: true})
}
render() {
return (
<div>
<CodeMirror
value={this.state.outputText}
options={{
mode: 'javascript',
lineNumbers: true,
}}
onChange={(editor, data, value) => {
this.setState({
runCode: false,
outputText: value,
})
}}
/>
<button onClick={this.runCode}>run code</button>
<div className="Output">
<pre>{this.state.runCode && this.state.outputText}</pre>
</div>
</div>
)
}
}
Demo - Output appended on click of button.
Demo1 - Outout appended as you type in.
You need to add a state in such situations:
export default class Code extends Component {
state={
value: ''
}
render() {
return (
<div>
<CodeMirror
value='console.log("Hello World")'
options={{
mode: "javascript",
lineNumbers: true
}}
onChange={(editor, data, value) => {
this.setState({value});
}}
/>
<button onClick={}>run code</button>
<div className="Output">
<p>{this.state.value}</p>
</div>
</div>
);
}
}
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>
I am wondering how to change a display few elements from hide to visible in React. I have 4 section and for each section button. Start section has start button, About section has about button, Skills section has skills button and Contact section has contact button. How to make it when im clicking Start all others sections get instantly display: none and only Skills section is visible? By clicking About button, others get hide (none) and only About is visible? Etc to others sections.
I know that i have to make a handleonclick but idk how.
Should it work with state?
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Start extends Component {
render() {
return (
<div className='start'>
</div>
);
}
}
class About extends Component {
render() {
return (
<div className='about'>
</div>
);
}
}
class Skills extends Component {
render() {
return (
<div className='skills'>
</div>
);
}
}
class Contact extends Component {
render() {
return (
<div className='contact'>
</div>
);
}
}
class Buttons extends Component {
render() {
return (
<div className="buttons">
<button>Start</button>
<button>About</button>
<button>Skills</button>
<button>Contact</button>
</div>
);
}
}
class App extends Component {
render() {
return (
<div className="App">
<Buttons />
<Main />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
<div id="root"></div>
<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>
Keep a state activeSection in the parent container called App. Then, pass it as a props to the child section components, About, Skills etc. Also add a method handleToggleSection, which you can call on click to the buttons and change the state activeSection to that corresponding section name. Inside all section components, About, Skills etc., check the current section name. If the name matches, then return the html or return null. Remember, when you return null, that component don't mount. If you want to keep the components mount regardless they are visible or not, then u need to use css classes like show, hide etc.
Here is the demo.
// import React from "react";
// import ReactDOM from "react-dom";
class Start extends React.Component {
get show() {
return this.props.activeSection === "start";
}
render() {
if (this.show) {
return <div className="start"> Start </div>;
} else {
return null;
}
}
}
class About extends React.Component {
get show() {
return this.props.activeSection === "about";
}
render() {
if (this.show) {
return <div className="about"> About </div>;
} else {
return null;
}
}
}
class Skills extends React.Component {
get show() {
return this.props.activeSection === "skills";
}
render() {
if (this.show) {
return <div className="skills"> Skills </div>;
} else {
return null;
}
}
}
class Contact extends React.Component {
get show() {
return this.props.activeSection === "contact";
}
render() {
if (this.show) {
return <div className="contact"> Contact </div>;
} else {
return null;
}
}
}
const Buttons = ({ onToggle }) => (
<div className="buttons">
<button name="start" onClick={onToggle}>
Start
</button>
<button name="about" onClick={onToggle}>
About
</button>
<button name="skills" onClick={onToggle}>
Skills
</button>
<button name="contact" onClick={onToggle}>
Contact
</button>
</div>
);
const Main = ({ activeSection }) => (
<React.Fragment>
<Start activeSection={activeSection} />
<About activeSection={activeSection} />
<Skills activeSection={activeSection} />
<Contact activeSection={activeSection} />
</React.Fragment>
);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activeSection: ""
};
this.handleToggleSection = this.handleToggleSection.bind(this);
}
handleToggleSection(e) {
const { name } = e.target;
this.setState(() => ({
activeSection: name
}));
}
render() {
return (
<div className="App">
<Buttons onToggle={this.handleToggleSection} />
<Main activeSection={this.state.activeSection} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
.App {
font-family: sans-serif;
text-align: center;
}
.show {
display: block;
}
.hide {
display: none;
}
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
You can use conditional rendering.
selectSection = section => {
this.setState({ section })
}
render() {
return (
<div className="App">
<Buttons onClick={this.selectSection} />
{this.state.section === "start" && <Start>}
{this.state.section === "about" && <About>}
</div>
);
}
Also, instead of the if you can use switch.