React Bootstrap OverlayTrigger not rearranging after popover content changes - reactjs

I have an issue when refreshing the content of a Popover using the OverlayTrigger. Basically, what I would expect is that if the content changes, the OverlayTrigger rearranges its position. But it doesn't.
Given the following code, that can be seen here: https://codesandbox.io/s/W6pDkDoyW
import React from 'react';
import { render } from 'react-dom';
import { Popover, OverlayTrigger } from 'react-bootstrap';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
names: ['george'],
};
this.loadMore = this.loadMore.bind(this);
this.setOld = this.setOld.bind(this);
}
loadMore() {
const _this = this;
setTimeout(() => {
_this.setState({ names: ['george', 'steve', 'peter'] });
}, 500);
}
setOld() {
this.setState({ names: ['george'] });
}
render() {
const popover = (
<Popover id="test-popover">
{this.state.names.map((n, index) =>
<p key={index}>
{n}
</p>,
)}
</Popover>
);
return (
<OverlayTrigger
trigger={['hover', 'focus']}
placement="top"
overlay={popover}
onEnter={this.loadMore}
onExit={this.setOld}
>
<span>This is a div</span>
</OverlayTrigger>
);
}
}
const Container = () => {
return (
<div
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
minHeight: '24em',
}}
>
<div style={{ maxWidth: '50%' }}>
<App />
</div>
</div>
);
};
render(<Container />, document.getElementById('root'));
Is this possible or not?

Related

React Select with avatar class component whats wrong here select not populating

Hi I had working select box with avatar on functional aporx. But I need build in functions to change selectbox properties like hidden: true/false, update option data function to add new option data to display selectbox with certain values on fly.
What I wrong here? Render part works as tested with functional version. The class factoring misses something as select box does not get info ether options and avatar to display and no width calculation happening.
Orginal functional code: https://codesandbox.io/s/react-select-longest-option-width-geunu?file=/src/App.js
Class based works but nodatin selectbox. Here is app.js with select.js fiddle: https://codesandbox.io/s/react-select-longest-option-width-forked-plqq0p?file=/src/Select.js
Source:
import React, { useRef } from "react";
import Select from "react-select";
class RtSelect extends React.Component {
constructor(props) {
super();
this.state = {
info: props.info,
options: props.options,
hidden: props.hidden,
menuIsOpen: false,
menuWidth: "",
IsCalculatingWidth: false
};
this.selectRef = React.createRef();
this.onMenuOpen = this.onMenuOpen.bind(this);
}
componentDidMount() {
if (!this.menuWidth && !this.isCalculatingWidth) {
setTimeout(() => {
this.setState({IsCalculatingWidth: true});
// setIsOpen doesn't trigger onOpenMenu, so calling internal method
this.selectRef.current.select.openMenu();
this.setState({MenuIsOpen: true});
}, 1);
}
}
onMenuOpen() {
if (!this.menuWidth && this.isCalculatingWidth) {
setTimeout(() => {
const width = this.selectRef.current.select.menuListRef.getBoundingClientRect()
.width;
this.setState({menuWidth: width});
this.setState({IsCalculatingWidth: false});
// setting isMenuOpen to undefined and closing menu
this.selectRef.current.select.onMenuClose();
this.setState({MenuIsOpen: true});
}, 1);
}
}
styles = {
menu: (css) => ({
...css,
width: "auto",
...(this.isCalculatingWidth && { height: 0, visibility: "hidden" })
}),
control: (css) => ({ ...css, display: "inline-flex " }),
valueContainer: (css) => ({
...css,
...(this.menuWidth && { width: this.menuWidth })
})
};
setData (props) {
this.setState({
info: props.info,
options: props.options,
hidden: props.hidden
})
}
render() {
return (
<div style={{ display: "flex" }}>
<div style={{ margin: "8px" }}>{this.info}</div>
<div>
<Select
ref={this.selectRef}
onMenuOpen={this.onMenuOpen}
options={this.options}
menuIsOpen={this.menuIsOpen}
styles={this.styles}
isDisabled={this.hidden}
formatOptionLabel={(options) => (
<div className="select-option" style={{ display: "flex" }}>
<div style={{ display: "inline", verticalAlign: "center" }}>
<img src={options.avatar} width="30px" alt="Avatar" />
</div>
<div style={{ display: "inline", marginLeft: "10px" }}>
<span>{options.label}</span>
</div>
</div>
)}
/>
</div>
</div>
);
}
}
export default RtSelect;
Got it working!
I had removed "undefined" from onOpen setState function. I compared those 2 fiddles and finally got it working.
// setting isMenuOpen to undefined and closing menu
this.selectRef.current.select.onMenuClose();
this.setState({MenuIsOpen: undefined});

There is two button, once click on the button the name of the button will render inside the id

Hi guys help me on this i am stuck for a project.
After the button click, the page should look like:
Example
Once click on the button the bellow text will call the color name just like the image
class ColorChange extends Component {
constructor(props) {
super(props);
this.state =
}
render() {
return null;
}
}
class App extends Component {
state = {
text: ''
}
onDocumentClick = (event) => {
if (event.target.tagName === 'BUTTON') {
this.setState({ text: event.target.textContent })
}
}
componentDidMount() {
document.addEventListener('click', this.onDocumentClick)
}
componentWillUnmount() {
document.removeEventListener('click', this.onDocumentClick)
}
render() {
return <div>
{this.props.children}
<Tooltip text={this.state.text}/>
</div>
}
}
<button id="btnGreen">Green</button>
<button id="btnRed">Red</button>
document.getElementById("button2").click();
You can use this code:
import { Component } from "react";
export default class App extends Component {
state = {
text: ""
};
render() {
return (
<div className="App">
<button
style={{
backgroundColor: "green",
color: "white",
cursor: "pointer"
}}
onClick={() => this.setState({ text: "GREEN" })}
>
GREEN
</button>
<button
style={{ backgroundColor: "red", color: "white", cursor: "pointer" }}
onClick={() => this.setState({ text: "RED" })}
>
RED
</button>
<br />
COLOR: {this.state.text}
</div>
);
}
}
You can take a look at this sandbox for a live working example.

Material-UI: ListItem onClick not called

I am working with React and Material-UI. I am trying to display a list and call a function when one of the items of the list is clicked.
The code below is a simplified version of my code, but it should contain all the lines concerning the issue.
The onClick function is apparently never called. What am I missing?
App.js:
import React, { Component } from 'react';
import './App.css';
import Grid from '#material-ui/core/Grid';
import Map from './Map.js';
class App extends Component {
render() {
return (
<div >
<Grid container spacing={24}>
<Grid item xs={3}>
Column text
</Grid>
<Grid item xs={9}>
<Map/>
</Grid>
</Grid>
</div>
);
}
}
export default App;
Map.js:
import React from 'react';
import List from '#material-ui/core/List';
import ListItem from '#material-ui/core/ListItem';
import ListItemText from '#material-ui/core/ListItemText';
class Map extends React.Component {
constructor(props) {
super(props);
this.state = {
sensorsList: {
isLoaded: false,
data: null,
},
};
}
componentDidMount() {
// retrieve list of sensors
fetch("https://api-of-things.plenar.io/api/sensors?size=10000")
.then(res => res.json())
.then(
(result) => {
this.setState({
sensorsList: {
isLoaded: true,
data: Object.keys(result.data).map(key => result.data[key].path),
}
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
error
});
}
)
}
selectSensor(name) {
console.log(name);
}
_renderSensorsList() {
const {sensorsList} = this.state;
return sensorsList.isLoaded && (
<div style={{
position: 'absolute',
zIndex: 1,
pointerEvents: 'none',
right: 10,
top: 10,
backgroundColor: 'white',
}}>
<List component="nav">
{ sensorsList.data.map(key =>
<ListItem button key={key} onClick={() => this.selectSensor("ciao")} >
<ListItemText primary={key} />
</ListItem>
)}
</List>
</div>
);
}
render() {
const {sensorsList, selectedSensor} = this.state;
return (
<div>
{ this._renderSensorsList() }
</div>
);
}
}
export default Map;
The problem is that in your div's style you are setting pointerEvents: 'none', preventing the click to reach the DOM event listener, remove it and it will work.
<div style={{
position: 'absolute',
zIndex: 1,
pointerEvents: 'none', //<---- remove this line
right: 10,
top: 10,
backgroundColor: 'white',
}}>
try replacing this
_renderSensorsList() {
with arrow function like this
_renderSensorsList = () => {

Render the same component twice on onClick in react

I am writing an electron application where I am using react for the UI. I am trying to add shapes(rectangle,square...), so I have created components for each of the shapes. And I have a list of shapes, when I click on the list the corresponding shapes are added. But I want to add the same shape twice which I am not able to do. Can someone help me here?
Below is my code.
List.js
import React from 'react';
class List extends React.Component{
render(){
return (
<div>
<li onClick={this.props.drawSquare}>Square</li>
<li onClick={this.props.drawRectangle}>Rectangle</li>
<li onClick={this.props.drawCircle}>Circle</li>
</div>
);
}
}
export default List
AppContainer.js
import React from 'react'
import List from '../components/List'
import Square from '../components/Square'
import Rect from '../components/Rect'
import Cir from '../components/Cir'
import But from '../components/basic/button'
const style={
position: 'fixed',
width: '800',
height: '800'
};
const butStyle={
position: 'relative',
top: '500px'
}
const style1={
borderStyle: 'groove',
position: 'fixed',
width: '500',
height: '500'
};
class AppContainer extends React.Component{
constructor(props) {
super(props);
this.state={squareclicked:0,
rectClicked:0,
circleClicked:0,};
}
drawSquare(){
console.log("inside square function");
this.setState({squareclicked:this.state.squareclicked+1})
console.log(this.state.squareclicked);
}
drawRectangle(){
console.log("inside rect function");
this.setState({rectClicked:this.state.rectClicked+1})
}
drawCircle(){
console.log("inside circle function");
this.setState({circleClicked:this.state.circleClicked+1})
}
render(){
console.log('render called');
return (
<div style={style}>
<div id="mainAppDiv" >
<List drawSquare={this.drawSquare.bind(this)}
drawRectangle={this.drawRectangle.bind(this)}
drawCircle={this.drawCircle.bind(this)}/>
<div id="shapeConatinerDiv" style={style1}>
{this.state.squareclicked}
{this.state.squareclicked > 0 && (<Square/>)}
{this.state.circleClicked > 0 && (<Cir/>)}
{this.state.rectClicked > 0 && (<Rect/>)}
</div>
</div>
<div style={butStyle}>
<But/>
</div>
</div>
);
}
}
export default AppContainer
Square.js
import React from 'react';
import ReactDOM from 'react-dom';
import {Rectangle} from 'react-shapes';
import Rnd from 'react-rnd'
import Modal from 'react-bootstrap/lib/Modal'
import ColorPallete from './Badging/ColorPalette'
import Button from 'react-bootstrap/lib/Button'
const style = {
border: 'solid 1px',
};
const style1={
position: 'fixed',
width: '500',
height: '500'
};
class Square extends React.Component{
constructor(props) {
super(props);
this.state={w:100,
h:100,
col:{color:'#ff0000'},
zIndex: 99,
modalShow: false,
};
}
close(){
this.setState({modalShow: false});
}
onDrag(){
console.log('hi');
}
onResi(dir, styleSize, clientSize, delta){
this.setState({w:clientSize.width});
this.setState({h:clientSize.height});
}
editSquare(){
this.setState({ modalShow: true });
}
render(props) {
return (
<Rnd ref={c => { this.rnd = c; }}
initial={{
x: parent.innerWidth / 2 - 700,
y: parent.innerHeight / 2 - 80,
width: this.state.w,
height: this.state.h,
}}
style={style}
minWidth={this.state.w}
minHeight={this.state.h}
maxWidth={500}
maxHeight={500}
bounds={'parent'}
lockAspectRatio={true}
onResize={this.onResi.bind(this)}
onDrag={this.onDrag.bind(this)}
>
<Rectangle width={this.state.w} height={this.state.h} fill={this.state.col} stroke={{color:'#E65243'}} strokeWidth={1} onClick={this.editSquare.bind(this)}/>
</Rnd >
);
}
}
export default Square
And the other shapes have the same kind of code.
Right now I am able to add only one square and when I click again nothing happens. But I am able to add other shapes which is once.
You'll want to add elements to an array and render the array of elements.
Here's some rough code that might help:
Component {
constructor() {
super(props)
this.state = { elements: [] }
}
render() {
return (<div>
<div onClick={()=>this.add()}>Add</div>
<div>{this.state.elements}</div>
</div>)
}
add() {
this.setState({
elements: this.state.elements.push(<div id={elements.length}>Element</div>)
})
}
}

react-burger-menu css does not work

I'm using burger-menu and i can't set CSS for the burger menu like the author guide: https://github.com/negomi/react-burger-menu
Here's my burger menu component:
import React from 'react';
import BurgerMenu from 'react-burger-menu';
import { List, ListItem, ListItemContent } from 'react-mdl';
var MenuWrap = React.createClass({
getInitialState() {
return {hidden : false};
},
toggle() {
this.setState({hidden: !this.state.hidden});
},
render() {
let style;
if (this.state.hidden) {
style = {display: 'none'};
}
return (
<div style={style} className={this.props.side}>
{this.props.children}
</div>
);
}
});
export default class LeftSidebar extends React.Component {
constructor(props) {
super(props);
this.state = {
currentMenu: 'push',
side: 'left',
hidden: true,
};
};
render() {
const Menu = BurgerMenu[this.state.currentMenu];
var styles = {
bmBurgerButton: {
position: 'fixed',
width: '36px',
height: '30px',
left: '36px',
top: '36px'
},
bmBurgerBars: {
background: '#373a47'
},
bmCrossButton: {
height: '24px',
width: '24px'
},
bmCross: {
background: '#bdc3c7'
},
bmMenu: {
background: '#373a47',
padding: '2.5em 1.5em 0',
fontSize: '1.15em'
},
bmMorphShape: {
fill: '#373a47'
},
bmItemList: {
color: '#b8b7ad',
padding: '0.8em'
},
bmOverlay: {
background: 'rgba(0, 0, 0, 0.3)'
}
};
return (
<MenuWrap wait={20}>
<Menu
style={styles}
noOverlay id={this.state.currentMenu}
pageWrapId={'page-wrap'}
outerContainerId={'outer-container'}
>
{console.log(Menu)}
<List>
<ListItem>
<ListItemContent icon="person">Dashboard</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent icon="person">Community</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent icon="person">About</ListItemContent>
</ListItem>
</List>
</Menu>
</MenuWrap>
);
}
};
And here is my main component:
import React from 'react';
import styles from './Main.scss';
import LeftSidebar from '../LeftSidebar/LeftSidebar'
export default class Program extends React.Component {
render() {
return (
<div id="outer-container" style={{height: '100%'}}>
<LeftSidebar />
<div id="page-wrap">
<p>Content</p>
</div>
</div>
);
}
}
All of the css from variable styles does not work.
EDIT: the problem above is solved by change style ={styles} to styles = {styles}. The other problem is: when i click close, the sidebar menu shift down about 10 or 20px before moving back to the left. How to remove that shift down effect?
Seems like you have a typo. It should be styles={styles} instead of style={styles}.

Resources