cmourglia
cmourglia

Reputation: 2534

Bad first positionning of the Dialogs when the content is too large

I am using material-ui^0.20 with react^16.2, and I have a problem when first showing up a Dialog which embeds a Component with too much content.

Here is a picture showing the problem :

enter image description here

And this is what should be showing up (and which is after closing the Dialog and showing it up a second time, or after a window resize, etc.)

enter image description here

Here is some source code reproducing the problem (online demo here, and the source code):

import React, { Component } from 'react';
import { render } from 'react-dom';

import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';

import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';

class BuggyComponent extends Component {
  render() {
    return <img src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" />
  }
}

class MyComponent extends React.Component {
  state = {
    open: false,
  };

  handleOpen = () => {
    this.setState({open: true});
  };

  handleClose = () => {
    this.setState({open: false});
  };

  render() {

    return (
      <div>
        <RaisedButton label="Buggy Dialog" onClick={this.handleOpen} />
        <Dialog
          title="Dialog"
          modal={false}
          open={this.state.open}
          onRequestClose={this.handleClose}
        >
          <BuggyComponent />
        </Dialog>
      </div>
    );
  }
}

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'React'
    };
  }

  render() {
    return (
      <MuiThemeProvider muiTheme={getMuiTheme({})}>
        <MyComponent /> 
      </MuiThemeProvider>
    );
  }
}

Is there something I can do to avoid this problem ? From what I could observe, not having a component inside a dialog, but the whole dialog as a component seems to correct this issue, but it's not very convenient, and not always possible.

Upvotes: 0

Views: 706

Answers (1)

Reason
Reason

Reputation: 1430

What happens here is this: Popup opens, material ui tries to center it and to center it, it tries to figure out the height of the content. At this point, the image is not available, so the contents (the image) does not have a height.

Image loads. Image now has a height, but the dialog is already positioned so this does not help.

You could try pre-loading the image (which is basically what happens later when it's updated). A hack-ish way to do this would be something like this:

<RaisedButton label="Buggy Dialog" onClick={this.handleOpen} />
<img src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" style={{width: '0', height: '0', visibility: 'hidden'}} />

This loads the image in an invisible img tag so the image is already loaded when the Dialog opens. The problem is that there is no guarantee that the image is loaded by the time the user clicks the button.

An alternative to this would be to detect when the image is loaded and then reposition the dialog. This works, but the downside is that once the image is loaded the dialog will jump, which may or may not be a problem.

class BuggyComponent extends Component {
    reRender() {
        this.props.dialog.forceUpdate();
    }

    render() {
        return <img onLoad={() => this.reRender()} src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" />
    }
}

<Dialog
    ref="dialog"
    repositionOnUpdate
    title="Dialog"
    modal={false}
    open={this.state.open}
    onRequestClose={this.handleClose}
>
    <BuggyComponent dialog={ this.refs.dialog} />
</Dialog>

A third option that only works when the height of the image is known is to explicitly set the height of the img-tag. This also prevents the need for a re-render when the image is loaded, but you will need to know the size beforehand.

A fourth option would be to change the function that opens the modal so that function preloads the image (if needed) before trying to open the modal.

The fifth and hopefully working option would be to make the custom component scrolling fixed size. This solves the problem of the unknown height, but requires you to determine what is a good fixed height which may or may not make sense depending on the content. To avoid having to worry too much about screen sizes, the height is expressed in vh.

class BuggyComponent extends Component {
    render() {
        return <div style={ {height: '70vh', overflow: 'scroll'} }>
            <img src="https://upload.wikimedia.org/wikipedia/commons/b/be/Random_pyramids.jpg" />
        </div>
    }
}

Upvotes: 2

Related Questions