Hello!
So, I found the following issue: on mobile phone, when I fill a TextField inside a Dialog, I have a weird behavior appearing:

The code for the Dialog is the following:
import React from 'react'
import Component from 'react/lib/ReactComponent'
import PureRenderMixin from 'react-addons-pure-render-mixin'
import Moment from 'moment'
import { Map, fromJS } from 'immutable'
import Dialog from 'material-ui/Dialog'
import FlatButton from 'material-ui/FlatButton'
import RaisedButton from 'material-ui/RaisedButton'
import FloatingActionButton from 'material-ui/FloatingActionButton'
import ContentAdd from 'material-ui/svg-icons/content/add'
import TextField from 'material-ui/TextField'
import SelectField from 'material-ui/SelectField'
import MenuItem from 'material-ui/MenuItem'
import DatePicker from 'material-ui/DatePicker/DatePicker'
import TimePicker from 'material-ui/TimePicker/TimePicker'
import AutoComplete from 'material-ui/AutoComplete'
import Divider from 'material-ui/Divider'
import * as Colors from 'material-ui/styles/colors'
import { categories, minDate, maxDate } from './Event'
const createStyle = {
position: 'fixed'
,right: 16
,bottom: 16
,zIndex: 100
}
const dialogStyle = {
width: '90%'
,minWidth: '320px'
,maxWidth: '1080px'
}
export default class CreateEvent extends Component {
constructor(props) {
super(props)
this.shouldComponentUpdate = PureRenderMixin
.shouldComponentUpdate.bind(this)
this.state = {
open: false
,owner: this.props.owner
,name: this.props.name
,startDay: this.props.startTime
,startTime: this.props.startTime
,endDay: this.props.endTime
,endTime: this.props.endTime
,description: this.props.description
,location: this.props.location
,category: this.props.category
,nameError: null
,startDayError: null
,startTimeError: null
,endDayError: null
,endTimeError: null
,descriptionError: null
,locationError: null
,categoryError: null
}}
componentWillReceiveProps(newProps) {
if (newProps.owner !== this.state.owner) {
this.setState({ owner: newProps.owner });
}
}
handleOpen() {
this.setState({ open: true })
}
handleOk() {
const fields = fromJS({
name: 'name'
,startDay: 'starting day'
,startTime: 'starting time'
,endDay: 'ending day'
,endTime: 'ending time'
,description: 'description'
,location: 'location'
,category: 'category'
})
const valid = fields.keySeq().reduce((valid, field) => {
if (!this.state[field] || this.state[field] === '') {
this.setState({
[field + 'Error']: 'The event ' + fields.get(field) +
' cannot be empty'
})
return false
}
return valid
}, true)
if (valid) {
const event = fromJS({
name: this.state.name
,startTime: Moment(
Moment(this.state.startDay).format('YYYY-MM-DD ') +
Moment(this.state.startTime).format('HH:mm:ss')
,'YYYY-MM-DD HH:mm:ss'
)
,endTime: Moment(
Moment(this.state.endDay).format('YYYY-MM-DD ') +
Moment(this.state.endTime).format('HH:mm:ss')
,'YYYY-MM-DD HH:mm:ss'
)
,owner: this.state.owner
,description: this.state.description
,location: this.state.location
,category: this.state.category.get('name')
})
if (event.get('endTime') > event.get('startTime')) {
(this.props.create) ?
this.props.postEvent(event) :
this.props.updateEvent(event, this.props.eventId)
this.setState({open: false})
} else {
this.setState({
endDayError: 'The ending day should be after the starting day'
,endTimeError: 'The ending time should be after the starting time'
})
}
}
}
handleCancel() {
this.setState({open: false})
}
handleNameChange(event) {
this.setState({
nameError: null
,name: event.target.value
})
}
handleLocationChange(text) {
this.setState({
locationError: null
,location: text
})
}
handleCategoryChange(event, index, value) {
this.setState({
categoryError: null
,category: value
})
}
handleStartDayChange(event, time) {
this.setState({
startDayError: null
,startDay: time
})
}
handleStartTimeChange(event, time) {
this.setState({
startTimeError: null
,startTime: time
})
}
handleEndDayChange(event, time) {
this.setState({
endDayError: null
,endDay: time
})
}
handleEndTimeChange(event, time) {
this.setState({
endTimeError: null
,endTime: time
})
}
handleDescriptionChange(event) {
this.setState({
descriptionError: null
,description: event.target.value
})
}
render() {
const actions = [
<FlatButton
label="Ok"
primary={true}
onTouchTap={::this.handleOk}
/>
,<FlatButton
label="Cancel"
secondary={true}
onTouchTap={::this.handleCancel}
/>
]
return (
<div>
{(this.props.create) ? (
<FloatingActionButton
style={createStyle}
backgroundColor={Colors.deepOrange700}
onTouchTap={::this.handleOpen}
>
<ContentAdd />
</FloatingActionButton>
) : (
<RaisedButton
label="Edit"
fullWidth={true}
primary={true}
onTouchTap={::this.handleOpen}
/>
)}
<Dialog
title={
(
(this.props.create) ?
"Create a new" :
"Edit " + ((this.props.isOwner) ? "your" : "this")
) +
" awesome event!"
}
titleStyle={(this.state.category) ?
{backgroundColor: this.state.category.get('bgColor') || 'white'} :
null}
actions={actions}
modal={false}
open={this.state.open}
onRequestClose={::this.handleCancel}
contentStyle={dialogStyle}
autoScrollBodyContent={true}
>
<TextField
hintText='Event title'
value={this.state.name}
errorText={this.state.nameError}
fullWidth={true}
onChange={::this.handleNameChange}
disabled={!this.props.isOwner && !this.props.create}
/>
<div className='container-fluid'>
<div className='col-sm-6 col-xs-12'>
<AutoComplete
hintText="Location"
errorText={this.state.locationError}
dataSource={[]}
onUpdateInput={::this.handleLocationChange}
searchText={this.state.location}
fullWidth={true}
/>
</div>
<div className='col-sm-6 col-xs-12'>
<SelectField
floatingLabelText="Category"
errorText={this.state.categoryError}
onChange={::this.handleCategoryChange}
value={this.state.category}
disabled={!this.props.isOwner && !this.props.create}
fullWidth={true}
labelStyle={(this.state.category) ?
{color: this.state.category.get('color') || 'white'} :
null}
>
{categories.map((category, index) => (
<MenuItem
key={index}
style={{color: category.get('color')}}
value={category}
primaryText={category.get('name')}
/>
))}
</SelectField>
</div>
</div>
<div className='col-sm-7 col-xs-12'>
<DatePicker
minDate={minDate}
maxDate={maxDate}
defaultDate={minDate}
disableYearSelection={true}
hintText="Start day"
errorText={this.state.startDayError}
fullWidth={true}
onChange={::this.handleStartDayChange}
value={this.state.startDay}
/>
</div>
<div className='col-sm-5 col-xs-offset-2 col-xs-10'>
<TimePicker
format='24hr'
hintText="Start time"
errorText={this.state.startTimeError}
fullWidth={true}
onChange={::this.handleStartTimeChange}
value={this.state.startTime}
/>
</div>
<div className='col-sm-7 col-xs-12'>
<DatePicker
minDate={minDate}
maxDate={maxDate}
defaultDate={maxDate}
disableYearSelection={true}
hintText="End day"
errorText={this.state.endDayError}
fullWidth={true}
onChange={::this.handleEndDayChange}
value={this.state.endDay}
/>
</div>
<div className='col-sm-5 col-xs-offset-2 col-xs-10'>
<TimePicker
format='24hr'
hintText="End time"
errorText={this.state.endTimeError}
fullWidth={true}
onChange={::this.handleEndTimeChange}
value={this.state.endTime}
/>
</div>
<TextField
hintText='Description'
errorText={this.state.descriptionError}
fullWidth={true}
multiLine={true}
onChange={::this.handleDescriptionChange}
value={this.state.description}
disabled={!this.props.isOwner && !this.props.create}
/>
</Dialog>
</div>
)
}
}
Hey @skasch, are you building a mobile app only or is this a web app thats mobile responsive? Reason I'm asking is I'm having trouble controlling my dialog component with media queries.
Hey @IrvingAxelB, I am building a responsive web app!
Try to add repositionOnUpdate={false} to Dialog component.
<Dialog
repositionOnUpdate={false}
open={this.props.open}
autoScrollBodyContent={true}
>
...
</Dialog>
There is still issue with using Dialog and TextField on Chrome on iPad when the onscreen keyboards opens.
First, the Safari on Ipad works much better. When tap on a TextField of a dialog, the keyboards shows up and the dialog doesn't resize or re-position with the following code. This is much better user experience. When the keyboard hides, there no re-positioning or resizing either.
With Chrome on iPad (not repro on Windows), when keyboard shows up after using start editing a TextField, the dialog will be resized. When the keyboard hides, the dialog will be repositioned to lower part of the screen.
Even worse when I use more complex control on the dialog such as RichText editing control, the dialog will be resized and repositioned out the screen.
<Dialog
title={dialogTitle}
actions={actions}
modal={false}
open={this.props.showDialog}
onRequestClose={this.handleClose}
bodyStyle={{overflow: 'auto', position: 'relative'}}
repositionOnUpdate={{false}}
autoScrollBodyContent={{true}}
autoDetectWindowHeight={{false}}
>
<div>{self.state.error}</div>
{controls}
</Dialog>
We've had huge problems with this and generally responsiveness of Dialog. Especially when opening keyboard on mobile devices. We are writing application that is responsive and should works on every device.
Second problem is that the gap between top screen and the top of dialog. It stays same for small devices.

For example in angular implementation it is smaller when the window height is smaller.

As a workaround we did some css tricks and we maximize it for small devices and it works well for mobile devices.

I expected similar behavior from mui's Dialog. It should occupy almost 100% of visible place on small devices to works well.
btw I tested how it works on phone and when screen height is too small my device displays only input field

It happens for example in some dialogs (with wifi settings) or in facebook application when adding new status. But not works in gmail app. So it have to be configured in Text Field component.
This issue was fixed along the way on the v1-beta branch.
Most helpful comment
Try to add
repositionOnUpdate={false}toDialogcomponent.