I am using Next.js and Material UI for a project.
My issue is that When Im using Material UI grid it doesn't stretch to its parent full Height.
Here is my index.tsx code:
import Head from 'next/head'
import styles from '../styles/Home.module.css'
import { useState } from 'react'
import Login from './login'
export default function Home() {
const [isConnected, setIsConnected] = useState(false)
return (
<>
<Head>
<title>Create Next App</title>
<meta name="description" content="Generated by create next app" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main style={{height: "100%", backgroundColor: "red"}}>
{isConnected? "AAA" : <Login/>}
</main>
</>
)
}
Here is my Login page code:
import { useState } from 'react';
import Box from '#mui/material/Box';
import Button from '#mui/material/Button';
import TextField from '#mui/material/TextField';
import styles from '../styles/Login.module.css'
import { Grid } from '#mui/material';
import { height } from '#mui/system';
interface LoginPageProps {
// Props go here
}
interface LoginPageState {
username: string;
password: string;
}
const LoginPage: React.FC<LoginPageProps> = (props: LoginPageProps) => {
const [state, setState] = useState<LoginPageState>({
username: '',
password: '',
});
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
if (name === 'username') {
setState({ ...state, username: value });
} else if (name === 'password') {
setState({ ...state, password: value });
}
};
const handleSignup = () => {
// Handle signup here
};
const handleSignin = () => {
// Handle signin here
};
return (
<Grid container
direction="row"
justifyContent="center"
alignItems="stretch" xs={12} sm={12} md={12}
style={{
backgroundColor: "green"
}}
>
<Grid item md={6}
direction="column"
>
<Grid item xs={12} sm={12} md={12}>
<Box
className="form"
component="form"
sx={{
height: "100%",
}}
>
<div
>
<TextField
label="Username"
variant="outlined"
name="username"
value={state.username}
onChange={handleChange}
fullWidth
/>
<TextField
label="Password"
variant="outlined"
type="password"
name="password"
value={state.password}
onChange={handleChange}
fullWidth
margin="normal"
/>
<div />
<Button className="signup" variant="contained" color="primary" onClick={handleSignup}>
Sign Up
</Button>
<Button className="signin" variant="contained" color="secondary" onClick={handleSignin}>
Sign In
</Button>
</div>
</Box>
</Grid>
</Grid>
<Grid item xs={6} sm={6} md={6}>
design
</Grid>
</Grid>
);
};
export default LoginPage;
Here is my global.css file and its the only styling not applied inline:
html, body, #__next {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
Im adding an img to clarify my issue.
red background is the main html tag - the parent
green background is the grid material ui component - the child
how to make the green component (the child) stretch its entire parent height?
Related
A dropdown field make the conatiner "scrollable" and cuts off the dropdown selections, selector must float above the container.
for other reasons I cannot change the overflow: auto in the outer container
Thanks for helping me
import "./styles.css";
import { useState, useRef, useEffect } from "react";
import styled from "styled-components";
export default function App() {
const ref = useRef(null);
const difference = useRef();
const [expanded, setExpanded] = useState(false);
useEffect(() => {
const height = ref.current.offsetHeight;
difference.current = height;
console.log(height);
}, [expanded]);
return (
<div
style={{ height: "60px", backgroundColor: "lightblue", overflow: "auto" }}
>
<div ref={ref} style={{ position: "relative" }}>
<span onClick={() => setExpanded((previousState) => !previousState)}>
See Options
</span>
{expanded && (
<div>
<div>
{["Option 1", "Option 2", "Option 3"].map((option, i) => (
<div
style={{
border: "1px solid green",
width: "60px"
}}
key={i}
onClick={(e) => {
e.stopPropagation();
console.log(option);
}}
>
{option}
</div>
))}
</div>
</div>
)}
</div>
</div>
);
}
Make your dropdown container have an absolute position, relative to the container it's in.
Absolute position means your parent container will ignore the width and height of the dropdown, which means the dropdown will not affect the height of the parent container.
Summary:
I have this logo in my website header, I want this logo (image [1]) to change to another one (image [2]) on scrolling down, and to change back to the original logo (image [1]) when I scroll back to the top.
What i tried:
I tried to make it with EventListener and useEffect in the header page, but I'm getting this error below:
ERROR in src\layouts\Navbar\index.jsx
Line 12:3: 'listenScrollEvent' is not defined no-undef
My code:
import React, { useState } from 'react'
import { useEffect } from "react";
export default () => {
useState = {
imageSrc: '',
imageAlt: ''
}
listenScrollEvent = e => {
if (window.scrollY > 400) {
this.setState({
imageSrc: './/img/Smartlogger_logo.png',
imageAlt: 'smartlogger white logo'
})
} else {
this.setState({
imageSrc: './../../views/Home/image/smartLoggerheader_logo.png',
imageAlt: 'smartlogger colored logo'
})
}
}
useEffect(() => {
window.addEventListener('scroll', this.listenScrollEvent)
}, []);
return (
<header className='header-area header-sticky'>
<div className='container'>
<div className='row'>
<div className='col-12'>
<nav className='main-nav'>
{/* ***** Logo Start ***** */}
<a href='/#' className='logo'>
<style>{css}</style>
<img
src={this.setState}
alt='Smartlogger logo'
/>
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
)
}
You need to make the following changes in your code. It should fix the issue.
Inside render() - img src replace src={this.setState} with src={this.state.imageSrc}
Inside listenScrollEvent function replace window.scrollY with event.srcElement.body.scrollY
it will look like this (I have used random images here):
listenScrollEvent = event => {
if (event.srcElement.body.scrollY > 400) {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger white logo'
})
} else {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger colored logo'
})
}
}
Full working code : (I have added style={{height:'200vh'}} on container div just to test it on my local. You can remove it)
import React from 'react'
import { Link } from 'react-router-dom'
export default class App extends React.Component {
state = {
imageSrc: 'https://c.tenor.com/TReUojNlZ6wAAAAi/js-javascript.gif',
imageAlt: ''
}
listenScrollEvent = event => {
if (event.srcElement.body.scrollY > 400) {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger white logo'
})
} else {
this.setState({
imageSrc: 'https://c.tenor.com/57w9du3NrV0AAAAS/css-html.gif',
imageAlt: 'smartlogger colored logo'
})
}
}
componentDidMount() {
window.addEventListener('scroll', this.listenScrollEvent)
}
render() {
return (
<header className='header-area header-sticky'>
<div className='container' style={{height:"200vh"}}>
<div className='row'>
<div className='col-12'>
<nav className='main-nav'>
{/* ***** Logo Start ***** */}
<a href='/#' className='logo'>
{/* <style>{css}</style> */}
<img
src={this.state.imageSrc}
alt='Smartlogger logo'
/>
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
)
}
}
Hope that's how you wanted it to work. Try running it on your local and then you can modify it as per your requiremnets.
In your useState hook you want to have your src and your alt.
Remember useState return an array of 2 elements, the first is the value and the second is the setter for that value.
You can use the setter in your listenScrollEvent function and you can use the value in your jsx.
You are also using a css variable in you jsx that isn't defined anywhere.
It should look something like this:
import React, { useState, useEffect } from "react";
export default () => {
const [image, setImage] = useState({
src: "",
alt: "",
});
const listenScrollEvent = (e) => {
if (window.scrollY > 400) {
setImage({
src: "../img/Smartlogger_white_logo.png",
alt: "smartlogger white logo",
});
} else {
setImage({
src: "../img/Smartlogger_colored_logo.png",
alt: "smartlogger colored logo",
});
}
};
useEffect(() => {
window.addEventListener("scroll", listenScrollEvent);
}, []);
return (
<header className="header-area header-sticky">
<div className="container">
<div className="row">
<div className="col-12">
<nav className="main-nav">
{/* ***** Logo Start ***** */}
<a href="/#" className="logo">
<style>{css}</style>
<img src={require(image.src)} alt={image.alt} />
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
);
};
An alternative solution that looks a little cleaner to me:
import React, { useState, useEffect } from "react";
import whiteLogo from "../img/Smartlogger_white_logo.png";
import coloredLogo from "../img/Smartlogger_colored_logo.png";
export default () => {
const [isScrolled, setIsScrolled] = useState(false);
const listenScrollEvent = (e) => setIsScrolled(window.scrollY > 400);
useEffect(() => {
window.addEventListener("scroll", listenScrollEvent);
}, []);
return (
<header className="header-area header-sticky">
<div className="container">
<div className="row">
<div className="col-12">
<nav className="main-nav">
{/* ***** Logo Start ***** */}
<a href="/#" className="logo">
<style>{css}</style>
<img
src={isScrolled ? whiteLogo : coloredLogo}
alt={
isScrolled
? "SmartLogger white logo"
: "SmartLogger colored logo"
}
/>
</a>
{/* ***** Logo End ***** */}
</nav>
</div>
</div>
</div>
</header>
);
};
EDIT: added note about css variable, fixed typo in code and formatted better
EDIT2: fixed image link and added the require in the img src attribute, this should fix the image loading
EDIT3: added alternative solution
I have a problem with React Final Form. I tried to follow the example on the official documentation, but I still don't understand why my form doesn't want to call the onSubmit as the example, and I'm still trying to understand what the role of handlesubmit is.
I think that the problem is that my fields are called from another component that uses the useField hook.
import React, { FC } from 'react'
import { Form, Field } from 'react-final-form'
import {
Grid,
Box,
Button,
createStyles,
makeStyles,
Theme,
} from '#material-ui/core'
import { render } from 'react-dom'
import InputField from './InputField'
interface InputFinalFormModalProps {
fieldsValue: { title: string; value: string }[]
}
const useStyles = makeStyles((theme: Theme) =>
createStyles({
annullaBtn: {
backgroundColor: '#fff',
border: `1px solid ${theme.palette.secondary.main}`,
color: theme.palette.secondary.main,
fontFamily: 'HouschkaHead',
fontSize: '17px',
fontWeight: 'bold',
paddingLeft: '40px',
paddingRight: '40px',
marginRight: '15px',
},
salvaBtn: {
fontFamily: 'HouschkaHead',
fontSize: '17px',
fontWeight: 'bold',
paddingLeft: '40px',
paddingRight: '40px',
marginLeft: '15px',
},
row: {
width: '100%',
textAlign: 'end',
},
container: {
'& > .MuiGrid-item': {
paddingBottom: '20px',
paddingTop: '0px',
paddingLeft: '11px',
paddingRight: '11px',
},
},
})
)
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
const onSubmit = async (values: {}) => {
await sleep(300)
console.log(JSON.stringify(values))
}
const validate = (values: {}) => {
const errors = {message: ''}
if (!Object.values(values).toString()) {
errors.message = "Required";
}
return errors
}
const InputFinalFormModal: FC<InputFinalFormModalProps> = ({ fieldsValue }) => {
const classes = useStyles()
return (
<Form
onSubmit={onSubmit}
validate={validate}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<Grid container className={classes.container}>
{fieldsValue.map((field) => {
return (
<InputField title={field.title} value={field.value} />
)
})}
</Grid>
<Box className={classes.row} mt="20px">
<Button className={classes.annullaBtn}>Annulla</Button>
<Button
type="submit"
onClick={() => onSubmit(values)}
className={classes.salvaBtn}
disabled={submitting || pristine}
>
Salva
</Button>
</Box>
{/* <button
type="submit"
onClick={() => onSubmit(values)}
disabled={submitting || pristine}
>
Submit
</button>
<button
type="button"
onClick={form.reset}
disabled={submitting || pristine}
>
Reset
</button>
<pre>{JSON.stringify(values)}</pre>*/}
</form>
)}
/>
)
}
InputFinalFormModal.displayName = 'InputFinalFormModal'
export default InputFinalFormModal
And here my snippet about the inputField
import React, { FC, useEffect, useState } from 'react'
import { useField } from 'react-final-form'
import {
Box,
Grid,
createStyles,
makeStyles,
Theme,
withStyles,
} from '#material-ui/core'
import InputLabel from '#material-ui/core/InputLabel'
import InputBase from '#material-ui/core/InputBase'
import { parse } from 'path'
interface InputFieldProps {
title: string
value: string
}
const BootstrapInput = withStyles((theme: Theme) =>
createStyles({
input: {
borderRadius: 4,
position: 'relative',
backgroundColor: theme.palette.common.white,
border: '1px solid #bdc7d3',
width: '100%',
padding: '10px 12px',
transition: theme.transitions.create(['border-color', 'box-shadow']),
// Use the system font instead of the default Roboto font.
fontFamily: 'Montserrat',
fontSize: '14px',
lineHeight: '1.21',
fontWeight: 'normal',
color: theme.palette.text.primary,
'&:focus': {
boxShadow: 'inset 0 0 12px 4px rgba(0, 179, 152, 0.05)',
borderColor: theme.palette.secondary.main,
},
},
})
)(InputBase)
const useStyles = makeStyles((theme: Theme) =>
createStyles({
inputTitle: {
color: '#7C92A8',
fontSize: '19px',
lineHeight: 1.76,
transition: 'font-weight 0.5s, color 0.5s',
'&.Mui-focused': {
color: theme.palette.secondary.main,
fontWeight: 'bold',
},
},
requiredText:{
color: 'red'
}
})
)
const InputField: FC<InputFieldProps> = ({ title, value}) => {
let {input, meta} = useField(title)
const classes = useStyles()
let [handleValidate, setHandleVlidate] = useState(false)
let [required, setRequired] = useState('')
useEffect(() => {
if(parseInt(value)){
setRequired('valore non valido')
setHandleVlidate(true)
/* if(isNaN(input.value)){
} */
}else{
if(!input.value){
setRequired('Campo Obbligatorio')
setHandleVlidate(true)
}
}
},[input.value])
return (
<Grid item xs={12} md={6}>
<InputLabel
shrink
htmlFor="bootstrap-input"
className={classes.inputTitle}
>
{title}
</InputLabel>
<BootstrapInput
{...input}
defaultValue={value}
id="bootstrap-input"
placeholder={value}
/>
{meta.touched && !input.value && (
<span className={classes.requiredText}>{required}</span>
)}
</Grid>
/* <Grid item xs={6} lg={6}>
<Box>
<label className={classes.inputTitle} onClick={() => console.log('check')}>{title}</label>
</Box>
<input {...field.input} className={classes.inputField} placeholder={value} />
{field.meta.touched && field.meta.error && (
<span>{field.meta.error}</span>
)}
</Grid> */
)
}
InputField.displayName = 'InputField'
export default InputField
If your form is valid, the validation function needs to return {}, not { message: '' }.
I did a google map with a list of resellers using "react-google-maps"
The markers properly looping and showing in the map
How can I list the 'Marker'/'Resellers' in the Map into a list(UL) too, Also the list(li) click should pop the info window?
This is the one I used, https://gist.github.com/jwo/43b382fc60eb09d3a415c9953f4057f8
import React, { Component } from "react"
import { compose } from "recompose"
import {
withScriptjs,
withGoogleMap,
GoogleMap,
Marker,
InfoWindow, Listing
} from "react-google-maps"
const MapWithAMarker = compose(withScriptjs, withGoogleMap)(props => {
const listStyle = {
width: '250px',
position: "relative"
}
return (
<div style={{ position: "relative" }}>
<GoogleMap defaultZoom={4} defaultCenter={{ lat: 56.263920, lng: 9.501785 }}>
{props.markers.map(marker => {
if (marker.lat != null) {
const onClick = props.onClick.bind(this, marker)
return (
<Marker
key={marker.customerNumber}
onClick={onClick}
position={{ lat: parseFloat(marker.lat), lng: parseFloat(marker.lng) }}
>
{props.selectedMarker === marker &&
<InfoWindow>
<div>
<h1> {marker.name}</h1>
<br />
{marker.address}
<br />
{marker.zipcode} {marker.city}
<br />
Telephone: {marker.phone}
</div>
</InfoWindow>}
{/* List resellers here, so info window can be reused I guess, not sure */}
</Marker>
)
}
})}
</GoogleMap>
</div>
)
})
export default class ResellerGoogleMap extends Component {
constructor(props) {
super(props);
this.state = {
showingInfoWindow: false,
selectedMarker: {},
selectedPlace: {}
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(marker, event) {
console.log(this.props)
this.setState({
selectedMarker: marker
});
}
render() {
return (
<div style={{ padding: "24px 13px 2px 2px" }}>
<input type="button" value="My Location" style={{ marginBottom: "20px" }} onClick={(e) => this.onBtnClick()} />
<MapWithAMarker
selectedMarker={this.state.selectedMarker}
markers={this.props.resellerData}
onClick={this.handleClick}
googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places"
loadingElement={<div style={{ height: `100%`, padding: `61px 55px 55px 55px` }} />}
containerElement={<div style={{ height: `800px` }} />}
mapElement={<div style={{ height: `511px` }} />}
/>
</div>
);
}
}
Expecting
a Google map/
Markers of 'resellers'/
List the resellers in a list too/
On click of list item should populate info window like when we click on Markers/
First two points are working, Need a hand on the rest, Please help somebody
Thank you all for your time, I found the solution
Simply we can add the following line of code just after the infowindow close tag
<a onClick={onClick}>{marker.name}</a>
I'm really confused with an issue I can't wrap my head around. For demonstration purposes, I included a vertical Menu component from Semantic UI. As you can see in the first picture, everything is normal and how I want it, but when I add a floated='right' tag to <Menu />, the bottom dividers disappear.
This is the way it's supposed to be:
This is what happens when the 'floated' tag is added:
import React, { Component } from 'react'
import { Header, Menu } from 'semantic-ui-react'
export default class MenuExampleText extends Component {
state = {}
handleItemClick = (e, { name }) => this.setState({ activeItem: name })
render() {
const { activeItem } = this.state
return (
<Menu vertical> // <Menu vertical floated='right'> removes the divider
<Menu.Item
name='promotions'
active={activeItem === 'promotions'}
onClick={this.handleItemClick}
>
<Header as='h4'>Promotions</Header>
<p>Check out our new promotions</p>
</Menu.Item>
<Menu.Item
name='coupons'
active={activeItem === 'coupons'}
onClick={this.handleItemClick}
>
<Header as='h4'>Coupons</Header>
<p>Check out our collection of coupons</p>
</Menu.Item>
<Menu.Item
name='rebates'
active={activeItem === 'rebates'}
onClick={this.handleItemClick}
>
<Header as='h4'>Rebates</Header>
<p>Visit our rebate forum for information on claiming rebates</p>
</Menu.Item>
</Menu>
)
}
}
Unless you can reproduce the issue for us or someone has experienced this issue before I'm not sure if anyone will be able to help you. Reproducing your menu in HTML and using float:right; does not appear to have the same issue.
Edit: Updated snippet to more closely follow your codepen and included css fix for display: none that was your accepted answer.
const {
Menu,
Header
} = semanticUIReact
class App extends React.Component {
state = {}
handleItemClick = (e, { name }) => this.setState({ activeItem: name })
render() {
const { activeItem } = this.state
return (
<Menu vertical style={styles.sidebarMenu} floated='right'>
<Menu.Item
name='promotions'
active={activeItem === 'promotions'}
onClick={this.handleItemClick}
>
<Header as='h4'>Promotions</Header>
<p>Check out our new promotions</p>
</Menu.Item>
<Menu.Item
name='coupons'
active={activeItem === 'coupons'}
onClick={this.handleItemClick}
>
<Header as='h4'>Coupons</Header>
<p>Check out our collection of coupons</p>
</Menu.Item>
<Menu.Item
name='deals'
active={activeItem === 'deals'}
onClick={this.handleItemClick}
>
<Header as='h4'>Deals</Header>
<p>Check out our collection of deals</p>
</Menu.Item>
<Menu.Item
name='rebates'
active={activeItem === 'rebates'}
onClick={this.handleItemClick}
>
<Header as='h4'>Rebates</Header>
<p>Visit our rebate forum for information on claiming rebates</p>
</Menu.Item>
</Menu>
)
}
}
const styles = {
sidebarMenu: {
marginLeft: 0,
marginRight: 0,
height: '100vh'
},
}
// ----------------------------------------
// Render
// ----------------------------------------
const mountNode = document.getElementById('react-app-mount')
ReactDOM.render(<App />, mountNode)
.ui.floated.menu .item:last-child:before {
display: block !important;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script>
<script src="https://unpkg.com/semantic-ui-react/dist/umd/semantic-ui-react.min.js"></script>
<div id="react-app-mount"></div>
For future viewers, the best solution I was able to come up with was creating a second menu within the menu item you are floating to the right. This should make it appear normal