I am using the react-modal npm package and wrapping it in my own component so I can re-use some of the behaviour and styling throughout my application.
What I want is to be able to encapsulate all the input modal dialog behaviour in a separate component and just insert it as a React tag in any page I want to use this dialog behaviour.
The problem I have is that I am not sure of the correct way to control the dialog open state. Currently I am maintaining this as a boolean property on the parent control state, and passing it through as a prop to the Dialog component, along with callbacks for close() and ok().
The problem is when the callbacks are executed when the user clicks the ok or close buttons, it then tries to call this.setState({ dialogOpen: true }) (or false) and "this" no longer seems to refer to the parent control, I'm guessing because it was executed from the dialog, so "this" now refers to the input dialog.
Can someone please suggest how I am implementing this incorrectly?
This is the error I get
TypeError: this.setState is not a function ./src/GridContent.tsx.GridContent.handleCloseModal [as closeDialog] C:/src/SignoffGui/src/GridContent.tsx:241 238 | } 239 | 240 | private handleCloseModal () {
241 | this.setState({ dialogOpen: false }); 242 | } 243 | 244 | private getActionButtonClass(expected:boolean, expression:boolean)
My parent control
interface IGridContentState {
dialogOpen: boolean
}
class GridContent extends React.Component<{},IGridContentState> {
constructor(props: any) {
super(props);
this.state = { dialogOpen: false};
this.handleOpenModal = this.handleOpenModal.bind(this);
}
public render() {
return (
<div className="Flex-Subcontainer" style={{margin:10}}>
<InputDialog
title="Please enter a reason for rejecting"
dialogOpen={this.state.dialogOpen}
submitText={this.handleRejectText}
closeDialog={this.handleCloseModal}
/>
<button onClick={(e) => this.doReject()}>Reject</button>
</div>
}
private doReject()
{
if (this.gridApi.getSelectedNodes().length > 0)
{
this.handleOpenModal();
}
}
private handleRejectText(enteredText: string)
{
this.props.signoffReject(this.getSelectedEntries(), enteredText);
this.gridApi.refreshCells();
}
private handleOpenModal () {
this.setState({ dialogOpen: true });
}
private handleCloseModal () {
this.setState({ dialogOpen: false });
}
}
And my dialog control
import * as React from 'react';
import * as ReactModal from 'react-modal';
import '../App.css';
interface IInputDialogProps
{
title: string,
dialogOpen: boolean,
submitText : (enteredText:string) => void,
closeDialog : () => void
}
interface IInputDialogState
{
enteredText: string
}
class InputDialog extends React.Component<IInputDialogProps, IInputDialogState> {
private input:React.RefObject<HTMLInputElement> = React.createRef();
constructor(props: IInputDialogProps) {
super(props);
this.state = { enteredText: ""};
this.handleCloseModal = this.handleCloseModal.bind(this);
}
public render() {
return (
<ReactModal
isOpen={this.props.dialogOpen}
// contentLabel="Example Modal"
// className="Modal"
// tslint:disable
onAfterOpen={() => this.input.current.focus()}
overlayClassName="Overlay"
shouldCloseOnEsc={true}
shouldReturnFocusAfterClose={true}
role="dialog"
onRequestClose={this.handleCloseModal}
shouldCloseOnOverlayClick={false}
ariaHideApp={false}
// tslint:disable
parentSelector={() => document.body}>
<div className="Modal-Container">
<div style={{flex:0.4}}>
<div className="Panel-header-left">
{this.props.title}
</div>
</div>
<div style={{flex:0.6}}>
<form onSubmit={(e) => this.processOkClicked()}>
<input ref={this.input} type="textbox" name="ModalInput" value={this.state.enteredText} onChange={ (e) => this.handleTextChanged(e)} />
</form>
</div>
<div>
<div className="Panel-header-right">
<button className="Action-Button" onClick={(e) => this.handleCloseModal()}>Cancel</button>
<button className="Action-Button" onClick={(e) => this.processOkClicked()}>OK</button>
</div>
</div>
</div>
</ReactModal>
);
}
private handleCloseModal () {
this.props.closeDialog();
}
private handleTextChanged(e:React.ChangeEvent<HTMLInputElement>) {
this.setState({ enteredText: e.target.value});
}
private processOkClicked () {
if (this.state.enteredText === "") return;
this.props.closeDialog();
this.props.submitText(this.state.enteredText);
}
}
export default InputDialog;