I cannot close the modal and dimmer in semantic - using react - reactjs

I'm trying to get a modal to close in react, using semantic modal. For some reason, I can get the form to close, but the dimmer remains. I need help.
I have tried $('.ui.modal').modal('hide dimmer') and many number of other things.
Modal is here:
export default class AddCamerModal extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Modal
id="add-camera-form"
trigger={<Button id="color-0093ee border-color-0093ee"
basic
icon="video-camera"
size="large"></Button>}
>
<Header icon='cube' content='New Object' />
<Modal.Content>
<AddCameraForm />
</Modal.Content>
</Modal>
)
}
Form is here:
export default class AddCameraForm extends React.Component {
constructor(props) {
super(props);
}
closeModal() {
$('.modal').modal('hide');
}
render() {
return (
<Form size="large">
<Form.Group widths="equal">
<Form.Field label='Name' control='input' placeholder='Name' name="name" id="name" required />
</Form.Group>
<Form.Group>
<Button type='submit' className="submit" onClick={this.handleSave}>Save</Button>
<Button type='deny' className="deny" onClick={this.closeModal}>Cancel</Button>
</Form.Group>
</Form>
)
}
}

You should pass 'open' prop false to your modal. You can do it via state or via props. For example:
export default class AddCamerModal extends React.Component {
constructor(props) {
super(props);
this.closeModal=this.closeModal.bind(this)
state={ isOpen: true }
}
closeModal() {
this.setState({isOpen: !this.state.isOpen});
}
render() {
return (
<Modal
open={this.props.open}
id="add-camera-form"
trigger={<Button id="color-0093ee border-color-0093ee"
basic
icon="video-camera"
size="large"></Button>}
>
<Header icon='cube' content='New Object' />
<Modal.Content>
<AddCameraForm closeModal={this.closeModal} />
</Modal.Content>
</Modal>
)
}
}
export default class AddCameraForm extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<Form size="large">
<Form.Group widths="equal">
<Form.Field label='Name' control='input' placeholder='Name' name="name" id="name" required />
</Form.Group>
<Form.Group>
<Button type='submit' className="submit" onClick={this.handleSave}>Save</Button>
<Button type='deny' className="deny" onClick={this.props.closeModal}>Cancel</Button>
</Form.Group>
</Form>
</div>
)
}
}

Maybe try this...
export default class AddCamerModal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false
};
}
render() {
return (
<Modal
id="add-camera-form"
open={this.state.open}
onClose={e => this.setState({ open: false })}
trigger={
<Button
id="color-0093ee border-color-0093ee"
basic
icon="video-camera"
size="large"
onClick={e => this.setState({ open: true })}
/>
}
>
<Header icon="cube" content="New Object" />
<Modal.Content>
<AddCameraForm />
</Modal.Content>
</Modal>
);
}
}

Okay, I want to post this just in case someone gets stuck in the same rabbit hole I was in. I had to set the open attribute in the modal, then pass that down to my AddCameraForm through the closeModal prop.
Here's the AddCameraModal:
export default class AddCameraModal extends React.Component {
constructor(props) {
super(props);
this.openModal=this.openModal.bind(this);
this.closeModal=this.closeModal.bind(this);
this.state = { isOpen: false }
}
openModal() {
this.setState({isOpen: true})
}
closeModal() {
this.setState({isOpen: false});
}
render() {
return (
<Modal
open={this.state.isOpen}
id="add-camera-form"
trigger={
<Button id="color-0093ee border-color-0093ee"
basic
icon="video-camera"
size="large" onClick={this.openModal}>
</Button>
}
>
<Header icon='cube' content='New Object' />
<Modal.Content>
<AddCameraForm closeModal={this.closeModal} openModal={this.openModal} />
</Modal.Content>
</Modal>
)
}
}
And here's the button's code from my AddCameraForm class:
<Button type='deny' className="cancel" onClick={this.props.closeModal}>Cancel</Button>

Related

Getting Data From React-Bootstrap Input

I am not finding good docs or videos on how to get data from my inputs with React-Bootstrap. I want to be able to click the button and then bring what I typed into the input box into my onClick function.
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.text = React.createRef();
this.searchChar = this.searchChar.bind(this);
}
searchChar = () => {
console.log("Button Clicked")
const value = this.input.current.value;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl ref = {this.input}
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
Just try to write your input values in state
for example;
import React from "react";
import Button from 'react-bootstrap/Button';
import './Search.css';
import InputGroup from 'react-bootstrap/InputGroup';
import FormControl from 'react-bootstrap/FormControl';
class search extends React.Component {
constructor(props){
super(props);
this.state = {
basicAddon1 : null,
};
}
searchChar = () => {
console.log("Button Clicked")
const value = this.state.basicAddon1;
console.log(value)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">Character Search</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={event => {
this.setState({
basicAddon1 : event.target.value
});
}}
value={this.state.basicAddon1 ? this.state.basicAddon1 : ""}
/>
</InputGroup>
<Button onClick={this.searchChar(this.input)} variant="outline-danger">Search </Button>
</form>
</div>
);
}
}
export default search;
you can create inputChangeHandler function or something else for improve your code
it just basic
The same way you deal with getting data from a form in pure React, you do with react-bootstrap. This answer here shows many options to do so.
My favourite approach among those options is this one. Using that approach your code would be something like:
class search extends React.Component {
constructor(props) {
super(props)
this.handleSave = this.handleSave.bind(this)
}
onChange(event) {
// Intended to run on the change of every form element
event.preventDefault()
this.setState({
[event.target.name]: event.target.value,
})
}
handleSave() {
console.log(`Do something with : {this.state.characterName}`)
}
render() {
return (
<div className="searchBar">
<form>
<InputGroup className="mb-3">
<InputGroup.Prepend>
<InputGroup.Text id="basic-addon1">
Character Search
</InputGroup.Text>
</InputGroup.Prepend>
<FormControl
name="characterName"
placeholder="Character Name"
aria-label="Character Name"
aria-describedby="basic-addon1"
onChange={this.onChange.bind(this)}
/>
</InputGroup>
<Button onClick={this.handleSave} variant="outline-danger">
Search{' '}
</Button>
</form>
</div>
)
}
}

React mui button input file not opening local machin file directory

I am trying to implement a button as an input field of file type, I have tried to wrap the input field with the button, and hide it. But, this is not working since nothing happens when I click on the button. I don't get the dialog to choose the files from the local machine. This is my component:
class MediaPlaceholder extends Component {
constructor(props){
super(props)
this.state = {
file: null
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
}
render() {
const {classes} = this.props;
return (
<Paper className={classes.media}>
<div>
<label htmlFor="upload-file">
<Button onClick={event => this.handleChange(event)}>
Add media...
<input
accept="image/*"
className={classes.input}
id="upload-file"
type="file"
/>
</Button>
</label>
</div>
</Paper>
);
}
}
I saw in few places that this is the suggested solution, so I am wondering why is it not working?
From the Material-UI docs/example https://material-ui.com/components/buttons/#contained-buttons :
<input
accept="image/*"
className={classes.input}
id="contained-button-file"
multiple
type="file"
/>
<label htmlFor="contained-button-file">
<Button variant="contained" component="span" className={classes.button}>
Upload
</Button>
</label>
So you could try :
class MediaPlaceholder extends Component {
constructor(props){
super(props)
this.state = {
file: null
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({
file: URL.createObjectURL(event.target.files[0])
})
}
render() {
const {classes} = this.props;
return (
<Paper className={classes.media}>
<div>
<input
accept="image/*"
className={classes.input}
id="upload-file"
type="file"
/>
<label htmlFor="upload-file">
<Button onClick={this.handleChange.bind(this)}>
Add media...
</Button>
</label>
</div>
</Paper>
);
}
}

Set state of parent from child component

I am working on this for hours now and I don't know what I have to do to make it work.
I have a parent component that has a child which is a modal dialogue. This dialogue has a date picker that has two attributes focused and onFocusChange.
The relevant parts of the parent component before the render() method:
class Terminkalender extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.setEventData = this.setEventData.bind(this);
this.selectElementPatient = this.selectElementPatient.bind(this);
this.handleDateChange = this.handleDateChange.bind(this);
this.toggleFocus = this.toggleFocus.bind(this);
moment.locale('de');
this.state = {
patient: null,
appointments: [{end: '2018-08-25T11:57:27.512Z', title: 'TEST', start: '2018-08-25T11:57:27.512Z'}],
time: '10:00',
inputValue: ''
}
}
componentDidMount() {
this.setState({
appointments: this.state.appointments.map(a => Object.assign({}, a, { end: new Date(a.end), start: new Date(a.start) })),
});
}
setEventData(event) {
this.setState({
timeStart: event.start.getHours() + ":" + event.start.getMinutes(),
timeEnd: event.end.getHours() + ":" + event.end.getMinutes(),
date: event,
disabled: true,
modal: !this.state.modal
});
}
toggle() {
this.setState({
modal: !this.state.modal
});
}
handleDateChange(newDate) {
this.setState({
date: newDate
});
}
toggleFocus(toggleFocused) {
this.setState({
focused: !this.state.focused
});
}
The child component in the parent component:
<AppointmentModal
focused={this.state.focused}
toggleFocus={this.toggleFocus}
patient={this.state.patient}
handleDateChange={this.handleDateChange}
date={this.state.date}
/>
Here is the date picker that uses focused and toggleFocus():
<SingleDatePicker
inputIconPosition="after"
block={false}
numberOfMonths={1}
date={this.props.date ? moment(this.props.date): null}
onDateChange={date => this.props.handleDateChange(date)}
focused={this.props.focused}
onFocusChange={this.props.toggleFocus}
/>
The problem I have now, is that the opening mechanism that is toggled by the function toggleFocus doesn't seem the work. When I click on the field of SingleDatePicker I can see in the console that focused is set two times to true.
What do I need to change so that if I click on the field and trigger the toggleFocus() function, I set focused to true and when I click out or click one date, it is set to false.
EDIT: The SingleDatePicker is from react-dates.
EDIT2, the render() method:
render() {
return (
<div className="animated">
<Card>
<CardBody style={{height: '50em'}}>
<Button type="submit" size="sm" color="success" className="mb-3 p-1"><i className="fa fa-plus"></i> Neuer Termin</Button>
<BigCalendar className="d-sm-down-none"
{...this.props}
selectable
events={this.state.appointments}
views={['month', 'week', 'day']}
step={15}
defaultDate={new Date(currYear, currMonth, 1)}
defaultView='week'
toolbar={true}
messages={{month:"Monat", week:"Woche", day:"Tag", today:"Heute", previous:"Zurück", next:"Weiter"}}
culture="de"
onSelectSlot={this.setEventData}
onSelectEvent={this.setEventData}
/>
<BigCalendar className="d-md-none"
{...this.props}
selectable
events={this.state.appointments}
views={['day']}
step={15}
defaultDate={new Date(currYear, currMonth, 1)}
defaultView='day'
toolbar={true}
messages={{day:"Tag"}}
culture="de"
/>
<AppointmentModal
timeStart={this.state.timeStart}
timeEnd={this.state.timeEnd}
modal={this.state.modal}
onChange={this.toggle}
selectElementPatient={this.selectElementPatient}
focused={this.state.focused}
toggleFocus={this.toggleFocus}
patient={this.state.patient}
handleDateChange={this.handleDateChange}
date={this.state.date}
/>
</CardBody>
</Card>
</div>
);
}
EDIT 3: The AppointmentModalcomponent:
class AppointmentModal extends Component {
constructor(props) {
super(props);
}
render() {
return (
<Modal isOpen={this.props.modal} toggle={this.props.onChange}>
<ModalHeader toggle={this.props.onChange}>Neuer Termin</ModalHeader>
<ModalBody>
<FormGroup row>
<Col md="3">
<Label htmlFor="anfang">Zeit:</Label>
</Col>
<Col xs="12" md="9">
<SingleDatePicker
inputIconPosition="after"
block={false}
numberOfMonths={1}
date={this.props.date ? moment(this.props.date): null}
onDateChange={date => this.props.handleDateChange(date)}
focused={this.props.focused}
onFocusChange={this.props.toggleFocus}
openDirection="down"
hideKeyboardShortcutsPanel={true}
placeholder="Tag"
displayFormat={() => moment.localeData().longDateFormat('L')}
/>
</Col>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={this.props.onChange}>Speichern</Button>{' '}
<Button color="secondary" onClick={this.props.onChange}>Abbrechen</Button>
</ModalFooter>
</Modal>
);
}
}
export default AppointmentModal;

How do I redirect to a new component after form onSubmit?

I'm doing Wes-Bos tutorial and thinking about another way to redirect to App.js component after the form is submitted from StorePicker.
My StorePicker component:
class StorePicker extends React.Component {
goToStore(event) {
event.preventDefault();
const storeId = this.storeInput.value;
return <Redirect to={`/store/${storeId}`} />;
}
render () {
return (
<Grid textAlign='center' columns={2}>
<Grid.Row>
<Grid.Column><br/>
<Segment>
<Form onSubmit={(e) => this.goToStore(e)} >
<Form.Field >
<h1>Store Name</h1>
<input type="text" required
placeholder="Store Name"
ref={(input) => {this.storeInput = input}}
defaultValue={getFunName()} />
</Form.Field>
<Button fluid type='submit'>Visit Store -></Button>
</Form>
</Segment>
</Grid.Column>
</Grid.Row>
</Grid>
)
}
}
I'm looking through React router documentation and trying to play around with it's <Redirect /> doesn't seem to work. Any advice how to manage this redirection? Thanks
You can use the history prop programmatically:
push(path, [state]) - (function) Pushes a new entry onto the history stack
class StorePicker extends React.Component {
goToStore = (event) => {
event.preventDefault();
this.props.history.push(`/store/${this.storeInput.value}`);
}
render() {
return (
<Grid textAlign="center" columns={2}>
<Grid.Row>
<Grid.Column>
<br />
<Segment>
<Form onSubmit={this.goToStore}>
<Form.Field>
<h1>Store Name</h1>
<input
type="text"
required
placeholder="Store Name"
ref={(input) => {
this.storeInput = input;
}}
defaultValue={getFunName()}
/>
</Form.Field>
<Button fluid type="submit">
Visit Store ->
</Button>
</Form>
</Segment>
</Grid.Column>
</Grid.Row>
</Grid>
);
}
}
There's also replace if you don't want to create an item in the history.
OK. I've manage to make it work looking through some other examples. My working code is below. It looks a bit complicated.
Is there a better way doing it?
class StorePicker extends React.Component {
constructor () {
super();
this.state = {
fireRedirect: false
}
}
goToStore(event) {
event.preventDefault();
this.setState({ fireRedirect: true })
}
render () {
const { from } = this.props.location.state || '/'
const { fireRedirect } = this.state
return (
<Grid textAlign='center' columns={2}>
<Grid.Row>
<Grid.Column><br/>
<Segment>
<Form onSubmit={(e) => this.goToStore(e)} >
<Form.Field >
<h1>Store Name</h1>
<input type="text" required
placeholder="Store Name"
ref={(input) => {this.storeInput = input}}
defaultValue={getFunName()} />
</Form.Field>
<Button fluid type='submit'>Visit Store -></Button>
</Form>
{fireRedirect && (
<Redirect to={from || `/store/${this.storeInput.value}`}/>)}
</Segment>
</Grid.Column>
</Grid.Row>
</Grid>
)
}
}

Developing a generic React component to open and close arbitrary forms

I got the following snippet to open and close forms on my page:
<div>
{this.state.editFormOpen?
<div>
<Link
to=''
onClick={()=>{this.setState({editFormOpen:false})}}>
Close
</Link>
<PostForm
onSubmit={(post)=>this.createPost(post)}
/>
</div>:
<Link
to=''
onClick={()=>{this.setState({editFormOpen:true})}}>
Add post
</Link>}
</div>
Now in order to avoid repeating myself, I want to refactore that code into a seperate <FormHandler/> component, such that it works for arbitrary forms, not only
<PostForm/>. I.e., I need to be able to pass any form component to the <FormHandler/>.
How can I do this in React?
I will go about it by making a factory that returns a React Component, than render the children as props
const FormHandlerFactory = ({Form = PostForm}) => {
return class FormHandler extends React.Component {
render() {
return (
<div>
{this.state.editFormOpen?
<div>
<Link
to=''
onClick={()=>{this.setState({editFormOpen:false})}}>
Close
</Link>
<Form
onSubmit={(post)=>this.createPost(post)}
/>
</div>:
<Link
to=''
onClick={()=>{this.setState({editFormOpen:true})}}>
Add post
</Link>}
</div>
)
}
}
}
You can use this factory as
const FormHandler = FormHandlerFactory({Form: YourCustomFormComponent});
const App = (props) => (
<Form {...props}
)
You could create a stateless component that could render any children that you passed in that component you also need to put the states in the parent component
const ToggleForm = ({ editFormOpen, editFormHandler, children }) => (
<div>
{editFormOpen?
<div>
<Link
to=''
onClick={() => editFormHandler(false)}>
Close
</Link>
{children}
</div>:
<Link
to=''
onClick={() => editFormHandler(true)}>
Add post
</Link>}
</div>
);
class ParentCmp extends React.Component {
constructor(props) {
super(props);
this.state = {
editFormOpen: false,
}
this.editFormHandler = this.editFormHandler.bind(this);
this.createPost = this.createPost.bind(this);
}
editFormHandler(boolValue) {
this.setState({
editFormOpen: boolValue
});
}
render() {
return (
<div>
<ToggleForm
editFormOpen={this.state.editFormOpen}
editFormHandler={this.state.editFormHandler}
>
<PostForm
onSubmit={(post)=>this.createPost(post)}
/>
</ToggleForm>
</div>
)
}
}
You already have everything you need in order to accomplish that. Maybe just change the line where you render PostForm and accept props.children coming from your new component. With that you will be able to render any form you want inside of it.
Remember that the less business logic you keep outside of FormHandler the better. Each form should be aware of what to do on every field change or on submit.
For example, this.createPost should not be part of FormHandler in case you want to reuse it throughout your code.
class FormHandler extends React.Component {
constructor(props) {
super(props)
this.state = {
formOpen: false,
}
this.toggleFormOpen = this.toggleFormOpen.bind(this)
}
toggleFormOpen() {
this.setState({
formOpen: !this.state.formOpen,
})
}
render() {
return (
<div>
<button onClick={this.toggleFormOpen}>
{this.state.formOpen ? 'Close' : 'Open'}
</button>
{this.state.formOpen && React.cloneElement(
this.props.children,
{
onClose: this.toggleFormOpen
}
)}
</div>
)
}
}
const PostForm = ({ onClose, onSubmit }) =>
<form>
<input type="text" placeholder="Post Name" />
<input type="text" placeholder="Post Title" />
<input type="text" placeholder="Date" />
<button onClick={event => {
event.preventDefault()
onSubmit({ postName: '', postTitle: '', date: ''})
onClose()
}}>
Submit
</button>
</form>
const UserForm = ({ onClose, onSubmit }) =>
<form>
<input type="text" placeholder="First Name" />
<input type="text" placeholder="Last Name" />
<button onClick={event => {
event.preventDefault()
onSubmit({ firstName: '', lastName: '' })
onClose()
}}>
Submit
</button>
</form>
const App = () =>
<div>
<FormHandler>
<PostForm
onSubmit={formData => console.log('PostForm', formData)}
/>
</FormHandler>
<br />
<FormHandler>
<UserForm
onSubmit={formData => console.log('UserForm', formData)}
/>
</FormHandler>
</div>
ReactDOM.render(
<App />,
document.getElementById('root')
)
<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="root"></div>

Resources