Popover in material-ui - display glitches when using components - reactjs

It's a trivial issue but I'm not seeing where the problem exactly lies.
As far as I know, React offers the ability to pull stuff apart into (somewhat) independent components which results in cleaner pages because not everything is crammed into one huge HTML file. Or so the philosophy goes, I think.
Basically, when I do this, everything works fine:
<Popover open={this.props.popover === LoginPopoverState.LOGIN}
anchorEl={this.props.anchorEl}
onRequestClose={this.handleHideLogin.bind(this, dispatch)}>
<div style={loginStyle}>
<TextField hintText="Username oder E-Mail" ref="username_login" floatingLabelText="Username / E-Mail"/><br />
<TextField hintText="Passwort" type="password" ref="password_login" floatingLabelText="Passwort" /><br />
<RaisedButton label="Login" onTouchTap={e => this.handleLoginTap(e, dispatch)} />
<p>Zur <a href="javascript://" onTouchTap={e => this.handleShowRegisterTap(e, dispatch)}>Registration</a>.</p>
</div>
</Popover>
Which looks like this:
However, when I pull out the <div> into another module and then do something like this:
import LoginFragment from './loginBar/LoginFragment.jsx'
<Popover open={this.props.popover === LoginPopoverState.LOGIN}
anchorEl={this.props.anchorEl}
onRequestClose={this.handleHideLogin.bind(this, dispatch)}>
<LoginFragment />
</Popover>
where LoginFragment.jsx contains something like this:
var LoginFragment = React.createClass({
render() {
return (
<TextField hintText="Username oder E-Mail" ref="username_login" floatingLabelText="Username / E-Mail"/>
)
}
})
Which results in this hot mess:
So, what is going on here?

It can be a CSS styling issue, since you arenĀ“t wrapping your fields inside a div anymore (and you are now skipping the loginStyle that was applied to this containing div.)
So, in the old version you had:
<Popover ...>
<div style={loginStyle}>
<TextField ...><br />
<TextField ...><br />
<RaisedButton .../>
<p>...</p>
</div>
</Popover>
But what you are including in your new version right now, using a single LoginFragment component, once expanded, would look like:
<Popover ...>
<TextField ...>
</Popover>
In this version, the wrapping divs (and their styling) would be missing. Including <div style={loginStyle}> in your code again would fix any CSS styling conflict, or help find and isolate the issue. Like so:
import LoginFragment from './loginBar/LoginFragment.jsx'
<Popover open={this.props.popover === LoginPopoverState.LOGIN}
anchorEl={this.props.anchorEl}
onRequestClose={this.handleHideLogin.bind(this, dispatch)}>
<div style={loginStyle}>
<LoginFragment />
</div>
</Popover>

Related

Which of the included styles should I choose when creating a new/edit form?

I have two forms: edit and new. They have different headers and a different set of buttons.
I always get bogged down in style. Which is preferred and why? Examples are showing edit form.
// inside FormImpl we look at mode to display a different header.
// inside FromImpl we look for the presence of onCancelEdit to show the cancel button.
<Form
render={form => (
<FormImpl form={form} mode="edit" onCancelEdit={handleCancelEdit} />
)}
/>
// header is controlled outside the form
// buttons and header live outside FormImpl
// formId is passed to the <form /> inside FormImpl
<Form
render={form => (<>
<h2>Edit</h2>
<FormImpl form={form} formId="main" />
<div>
<button for="main" type="submit">Submit</button>
<button onClick={handleCancelEdit}>Cancel</button>
</div>
</>)}
/>
// header is controlled outside the form
// slot the buttons, giving FormImpl the responsibility of placing them where needed.
<Form
render={form => (<>
<h2>Edit</h2>
<FormImpl
form={form}
buttons={
<div>
<button type="submit">Submit</button>
<button onClick={handleCancelEdit}>Cancel</button>
</div>
}
</>)}
/>
I've tried all three. This pattern comes up a lot and it's not always clear what to use. I'm using this as a learning exercise.

How do I use the SpeedDial to upload a file?

(this seem to have been asked previously but I couldn't find any hint on if it was actually answered)
MUI has a good demo for creating upload buttons which boils down to:
<input accept="image/*" className={classes.input} id="icon-button-file" type="file" />
<label htmlFor="icon-button-file">
<IconButton color="primary" aria-label="upload picture" component="span">
<PhotoCamera />
</IconButton>
</label>
What I wonder is how to implement the same using the Speed Dial. Inherently the SpeedDialAction seems to materialize as a <button/>, but it's not possible to e.g. wrap the SpeedDialAction in a <label htmlFor /> as its parent will try to set some props on it and will fail.
So how do I initiate the file selection from within the Speed Dial or a FAB in general?
You can create a wrapper component that forwards props to SpeedDialAction.
function UploadSpeedDialAction(props) {
return (
<React.Fragment>
<input
accept="image/*"
style={{ display: "none" }}
id="icon-button-file"
type="file"
/>
<label htmlFor="icon-button-file">
<SpeedDialAction
icon={<CloudUploadIcon />}
tooltipTitle="upload"
component="span"
{...props}
></SpeedDialAction>
</label>
</React.Fragment>
);
}
https://codesandbox.io/s/material-demo-forked-h6s4l
(Note to future readers: For v5, time allowing, we hope to rationalise where props rather than context are used to control children, in order to solve exactly this kind of issue. So check whether this solution is still needed.)
It is - in my knowledge - not possible to add the htmlFor in any way. So what I would do is to add a hidden input type file and then add a ref to it. Then in the onclick of the SpeedDialAction button I would call a handler function that clicks on the input ref. Like this:
const inputRef = useRef();
const handleFileUploadClick = () => {
inputRef.current.click();
};
Then your SpeedDialAction:
<SpeedDialAction
onClick={handleFileUploadClick}
... the rest of your props
/>
And then finnaly your actual input:
<input
style={{ display: "none" }}
ref={inputRef}
accept="image/*"
id="contained-button-file"
multiple
type="file"
/>
Working demo: https://codesandbox.io/s/material-demo-forked-f9i6q?file=/demo.tsx:1691-1868

How to use <br/> in string to put string in new line?

I was creating React project and here is the component that I want to ensure that is put inside a string.
<InfoIcon
tooltip={`${hints.todoHint} <br/> ${hints.inProgressHint} <br/> ${hints.doneHint}`}
/>
but it is not working since br/ is literally rendered like br/
One option is to convert tooltip in to three props and add <br /> in the InfoIcon component. For example InfoIcon component can be
const InfoIcon = ({ todoHint, inProgressHint, doneHint }) => (
<div>
{todoHint}
<br />
{inProgressHint}
<br />
{doneHint}
</div>
);
// Using Info Icon
<InfoIcon todoHint={todoHint} inProgressHint={inProgressHint} doneHint={doneHint} />
Other option is to send tooltip as follows
const tooltip = (
<div>
{hints.todoHint}
<br />
{hints.inProgressHint}
<br />
{hints.doneHint}
</div>
)
<InfoIcon tooltip={tooltip} />
Well, material-ui tooltip allows you to use ANY kind of HTML content. => refer to official document customized tooltiops
This means you can use normal <div> and <Typography />, and any other styled elements to handle multi-line content.
The only thing you need to do is pass the content to props title => refer to document of tooltip api
import {
Tooltip,
Typography
} from '#material-ui/core';
<Tooltip
title={ // customized content here via props `title`
<>
<div>Seperate line</div>
<Typography>Seperate line</Typography>
</>
}
>
<IconButton aria-label="delete">
<InfoIcon /> // You can use your original icon here
</IconButton>
</Tooltip>
Watch it online: https://stackblitz.com/run
You can find related question here: How to make line break for ToolTip titles in Material-UI

HintText of a TextField component in Material UI does not hide its value when start typing into the field

I have recently started exploring Material UI and I have run into this strange behavior of a hintText in a TextField Component(the one from Material UI)
This is my code:
/* in my component ... */
/* ... */
render() {
const actions = [
<FlatButton
key="1"
label="Cancel"
primary
onTouchTap={this.handleClose}
/>,
<FlatButton
key="2"
label="Submit"
primary
type="submit"
onTouchTap={this.handleSubmit}
/>
];
return (
<div>
<IconButton
tooltip="Add Asset"
onTouchTap={this.handleOpen}>
<Add color={"#000"} />
</IconButton>
<Dialog
title="Add"
actions={actions}
modal
open={this.state.open}>
<form>
<TextField hintText="Type"
value={this.state.name}
onChange={this.handleName}/>
</form>
</Dialog>
</div>
);
}
So when I start typing in the textfield, the hinttext remains, resulting in unreadable text due to letters over another letters.
I would really appreciate it if someone could help me. :)
image
Try using placholder="Type" rather than hintText="Type".
The solution for this is that you will have to update the variable name in the function handleName everytime the user updates the field. So the complete code is:
<TextField
hintText="Type"
value={this.state.name}
onChange={this.handleName}
/>
and the function handleName:
handleName=(event)=>{
this.setState({name:event.target.value});
}
It should work. If not, let me know in the comments below!

Material UI components not working in React

I have the following code snippet, which doesn't display anything at all in the browser window. Can you please tell me why.
render(){
return (
<div>
//Rama
//console.log('In Render'),
<div>
enter code here
<div>
<TextField
hintText="Username"
/>
<br/>
<TextField
hintText="Password"
/>
<br/>
<RaisedButton label="Login" primary={true} />
</div>
<div>
<TextField>Login Successful</TextField>
</div>
</div>
)
}
pastebin link for complete component: http://pastebin.com/etjUwvWT
To render material-ui components you need to wrap them in MuiThemeProvider.
As Per DOC:
Beginning with v0.15.0, Material-UI components require a theme to be
provided. The quickest way to get up and running is by using the
MuiThemeProvider to inject the theme into your application context.
How to use these components?
First use this line to import MuiThemeProvider :
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
Use this render method:
render(){
return (
<MuiThemeProvider muiTheme={getMuiTheme()}>
<div>
<div>
<TextField
hintText="Username"
/>
<br/>
<TextField
hintText="Password"
/>
<br/>
<RaisedButton label="Login" primary={true} />
</div>
<div>
<TextField/>
</div>
</div>
</MuiThemeProvider>
);
}
If you are using material-ui components across the project then no need to use MuiThemeProvider on each page, you also include it globally. Include this in your router or put this line on main page of the application.
One more thing you are only importing the injectTapEventPlugin, you need to initialise that also. Put this line in this component after importing:
injectTapEventPlugin();
Looks like you're having JS-comments (//) in your JSX code. That'll make stuff break.
If you want to comment something out in JSX, you have to escape into JS with curly brackets and then use multi line comments (/* comment */) - like so:
render() {
return (
<div>
{/* <button>Commented out button</button>*/}
</div>
);
}
Remove text from between the TextField tags. Also wrap your code in your render method between MuiThemeProvider.
This worked for me.
render(){
return (
<MuiThemeProvider>
<div>
<div>
<TextField
hintText="Username"
/><br/>
<TextField
hintText="Password"
/><br/>
<RaisedButton label="Login" primary={true} />
</div>
<div>
<TextField></TextField>
</div>
</div>
</MuiThemeProvider>
);
}
As an FYI, so it is not the most obvious responses, but just in case this is your situation, my issue was that I had changed my Windows 10 personalise settings to use contrast and my blue bar in my React app disappeared! After a while of searching, I switched it off and my bar was back.

Resources