Make react-leaflet map component resize itself to fit available space - react-leaflet

Setting the width of the Map component works, but height seems to only respond to an absolute size in pixels.
Is it possible to make the map control automatically consume available space inside the parent element?

I was able to create a component that passed in a component state value for the height of the map. I created a helper function that would resize the height to make it all responsive.
...
export default class MapContainer extends React.Component {
updateDimensions() {
const height = window.innerWidth >= 992 ? window.innerHeight : 400
this.setState({ height: height })
}
componentWillMount() {
this.updateDimensions()
}
componentDidMount() {
window.addEventListener("resize", this.updateDimensions.bind(this))
}
componentWillUnmount() {
window.removeEventListener("resize", this.updateDimensions.bind(this))
}
...
render() {
...
return (
<div class="map-container" style={{ height: this.state.height }}>
<Map>
...
</Map>
</div>
)
}
}

I solved this by using the react-container-dimensions component, which passes width/height as props to its child:
<div className="div that can resize""
ContainerDimensions>
<MyMapContainer/>
</ContainerDimensions>
</div>
...
style.width = Math.floor(this.props.width);
return (
<Map style={style}

Setting min-height & height to 100% on MapContainer worked form me:
<div style={{ height: "175px" }}><MapContainer style={{ height: "100%", minHeight: "100%" }} ...</div>

I solved this by setting the height of leaflet-container to 100% in my .css file.
.leaflet-container {
height: 100%;
}
With my Map component looking like this:
const Map = () => {
return (
<MapContainer center={[51.4381, 5.4752]} zoom={10} >
<TileLayer
maxZoom='20'
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
</MapContainer>
)
}
export default Map;

Related

AgGrid Custom Cell Editor does not refresh when calling refreshCells()

TLDR; the cell editor does not rerender when we invoke the api.refreshCells method.
The following code renders a simple table with 2 rows. The value of the data is irrelevant since it uses both a custom cell renderer and a custom cell editor that reaches into context to pluck a value.
When context updates we need to call refreshCells, since no change is detected to the actual cell data value.
Note when clicking increment the value of the context is incremented and the value of the cells updates accordingly. Observe the console log messages for each view renderer.
Now double click cell to enter into edit mode and then click the increment button. Note that the cell editor is not re-rendered when the increment takes place.
I can get the editor to update using events but the props (and so the context) are stale.
Presume this is a design decision, but I need to rerender the cell editor component when my context data updates. Any ideas?
https://plnkr.co/edit/3cCRnAY14nOWt3tl?open=index.jsx
const EditRenderer = (props) => {
console.log('render edit cell')
return (
<input
value={props.context.appContext.cellValue}
/>
);
};
const ViewRenderer = (props) => {
console.log('render view cell')
return <React.Fragment>{props.context.appContext.cellValue}</React.Fragment>;
};
const Grid = () => {
const [rowData] = useState([{ number: 10 }, { number: 3 }]);
const columnDefs = useMemo(
() => [
{
field: 'number',
cellEditor: EditRenderer,
cellRenderer: ViewRenderer,
editable: true,
width: 200,
},
],
[]
);
const [context, setContext] = useState({ cellValue: 1 });
const gridApiRef = useRef();
return (
<React.Fragment>
<p>Context value: {JSON.stringify(context)}</p>
<button
onClick={() => {
setContext({ cellValue: context.cellValue += 1 });
gridApiRef.current.refreshCells({force: true});
}}
>
Increment
</button>
<div style={{ width: '100%', height: '100%' }}>
<div
style={{
height: '400px',
width: '200px',
}}
className="ag-theme-alpine test-grid"
>
<AgGridReact
onGridReady={(e) => {
gridApiRef.current = e.api;
}}
context={{ appContext: context }}
columnDefs={columnDefs}
rowData={rowData}
/>
</div>
</div>
</React.Fragment>
);
};
render(<Grid />, document.querySelector('#root'));

react-mapbox-gl markers are not displayed correctly

I have a site with mapbox, the map itself works fine, but I can't add markers to it.
I copied the code from one source on which everything works, but when I added it to my project, the markers shifted from the correct coordinates on the map and got even more shifted when approaching.
here's my code
import React, { useState } from "react";
import ReactDOM from "react-dom";
import ReactMapboxGl, { Layer, Marker } from "react-mapbox-gl";
import { observer } from "mobx-react-lite";
import state from "../../state/state";
const Map = ReactMapboxGl({
accessToken:
"pk.eyJ1IjoibmFnaHQiLCJhIjoiY2wyYTJrazZxMDFlbzNpbnp0eTNnOG44aCJ9.i3nyiAJBTDyWviIWhsX-Zg",
});
const IndexMap = observer(({ coordinats }) => {
return (
<div style={{ height: "100vh", width: "100%", overflow: "hidden" }}>
<Map
style="mapbox://styles/mapbox/streets-v9" // eslint-disable-line
containerStyle={{
height: "100%",
width: "100%",
}}
center={{
lat: 51.5285582,
lng: -0.2416815,
}}
zoom={[12]}
>
<Marker coordinates={[-0.2416815, 51.5285582]} anchor="bottom">
<h1>marker</h1>
</Marker>
</Map>
</div>
);
});
export default IndexMap;
I think there are not enough styles for the map to set them in the right location.
I don't know what the problem was. I just moved the project to the folder with the working file. The link to the folder with the working file -https://codesandbox.io/embed/pwly8?codemirror=1

How can I have a Dynamic Image uri that is not always defined in React Native?

I am trying to get the filename of my image from a fetch to my rest service. But React tries to require the image before the call has the filename so ofcourse it can't find the image and gives me a 500 error back.
Is there any way to solve or work around this?
I am trying to get the filename from a json which it gets back from the fetch.
The function in which this is supposed to happen
nextPerson = () => {
var numberOfPersons = Object.keys(this.state.peopleList).length;
if (this.state.personIndex < numberOfPersons) {
person = this.state.peopleList[this.state.personIndex]
this.setState({currentPerson:person});
this.setState({image : require('../img/' + Object(this.state.currentPerson.gebruikerFoto).url)});
this.state.personIndex++;
}
}
The render of my component
render() {
var img = this.state.image;
return (
<View style={styles.container}>
<Image style={styles.image} source={img} />
<Text style={styles.persoonNaam}>{this.state.currentPerson.gebruikerNaam}</Text>
<Text style={styles.persoonBio}>{this.state.currentPerson.biografie}</Text>
<TouchableOpacity onPress={this.likePersoon}>
<Text>Like</Text>
</TouchableOpacity>
</View>
);
}
You need to keep your component in loading state, by rendering a shimmer component (react-native-shimmer) or just use ActivityIndicator from react native, until your api call finishes. Once the data is available you can render the Image component.
render() {
if (!this.state.imageUri) return <ActivityIndicator />; // keep showing the loader until the api call is done. Update the state once the call is successful.
return (
<Image /> // your image component
)
see this example:
renderItem = ({item})=>{
return(
<TouchableOpacity onPress={ () => this._openViewPage(item.id, item.cat_id,this.state.token)} style={styles.boxContainer}>
<View style={styles.BoxLeft}>
<H1>{item.title}</H1>
<H2 style={{flexWrap: 'wrap', textAlign: 'right',}}>{item.short_description}</H2>
</View>
<View style={styles.boxRight}>
<Image source={{uri: item.image}} style={{width: 100, height: 100 }} />
</View>
</TouchableOpacity>
)
}
annd in the render of your component you can use it:
<FlatList
data= {this.state.dataSource}
renderItem={this.renderItem}
keyExtractor = { (item, index) => index.toString() }
style={{marginBottom:100}}
/>

Material-UI Style Override?

I'm updating my app from Material-UI v1 to v2. I'm trying to use a style override to set the color of a selected <BottomNavigationAction> element.
const styles = {
bottomNavStyle: {
position: 'fixed',
left: '0px',
bottom: '0px',
height: '50px',
width: '100%',
zIndex: '100'
},
'&$selected': {
color: "#00bcd4" //<==trying to add this color to selected items
},
};
class bottom_nav extends Component {
state = {
selectedIndex: -1,
};
handleChange = (event, value) => {
this.setState({value});
};
render() {
const { classes } = this.props;
return (
<Paper className={classes.bottomNavStyle}>
<BottomNavigation
value={this.props.selectedBottomNavIndex}
onChange={this.handleChange}
showLabels
>
<BottomNavigationAction
label="Appointments"
icon={theApptsIcon}
/>
<BottomNavigationAction
label="Contacts"
icon={theEmailIcon}
/>
<BottomNavigationAction
label="Video Call"
icon={theVideoCall}
/>
</BottomNavigation>
</Paper>
);
}
}
export default withStyles(styles)(bottom_nav);
But, this does not do anything to the color of selected items.
I've read the Material-UI docs on CSS in JS and JSS, but haven't quite gotten it yet. What is the correct syntax for this?
UPDATE
Based on a response to this thread I've tried this:
const styles = {
bottomNavStyle: {
position: 'fixed',
left: '0px',
bottom: '0px',
height: '50px',
width: '100%',
zIndex: '100'
},
actionItemStyle: {
'&$selected': {
color: "#00bcd4 !important"
},
},
}
[.....]
return (
<Paper className={classes.bottomNavStyle}>
<BottomNavigation
value={this.props.selectedBottomNavIndex}
onChange={this.handleChange}
showLabels
>
<BottomNavigationAction
label="Appointments"
icon={theApptsIcon}
className={classes.actionItemStyle}
/>
<BottomNavigationAction
label="Contacts"
icon={theEmailIcon}
className={classes.actionItemStyle}
/>
<BottomNavigationAction
label="Video Call"
icon={theVideoCall}
className={classes.actionItemStyle}
/>
</BottomNavigation>
</Paper>
);
}
...but have not yet gotten the new color to appear on the web page.
Your updated solution looks good, there are just a few small changes...
You need to include an empty .selected class in your styles rules.
const styles = {
// Root styles for `BottomNavigationAction` component
actionItemStyles: {
"&$selected": {
color: "red"
}
},
// This is required for the '&$selected' selector to work
selected: {}
};
You need to pass classes={{selected: classes.selected}} to BottomNavigationAction. This is required for the '&$selected' selector to work.
<BottomNavigation
value={value}
onChange={this.handleChange}
className={classes.root}
>
<BottomNavigationAction
classes={{
root: classes.actionItemStyles,
selected: classes.selected
}}
label="Recents"
value="recents"
icon={<RestoreIcon />}
/>
</BottomNavigation>
Live Example:
There are couple of things I would like to suggest.
1) Write the name of the component with first letter capitalized since it is not treated the same way if it is named with small first letter and with capitalized.
2) If there is no other way for your cs rule to be applied, if it is overridden always because of some css specificity, use !iportant at the end of the rule.
3) Try this type of nesting of css in jss:
const styles = {
bottomNavStyle: {
position: 'fixed',
left: '0px',
bottom: '0px',
height: '50px',
width: '100%',
zIndex: '100',
'&:selected': {
color: "#00bcd4"
},
},
};

Styling react-select v2 with material-ui - Replace Input component

I'm having an issue with replacing the Input component for react-select v2 with the Input component from Material UI.
I've made an attempt so far in the codesandbox below, but unable to invoke the filtering upon typing into the Input?
https://codesandbox.io/s/jjjwoj3yz9
Also, any feedback on the Option replacement implementation would be appreciated. Am I going about it the right way with grabbing the text of the clicked option and search for the Option object from my options list to pass to the selectOption function?
Much appreciated,
Eric
V1
refer the documentation from here : https://material-ui.com/demos/autocomplete/
it provides clear documentation about how to use react-select with material-ui
here is a working example for your question: https://codesandbox.io/s/p9jpl9l827
as you can see material-ui Input component can take react-select as inputComponent.
V2
It's almost same as the previous approach :
implement the Input component:
<div className={classes.root}>
<Input
fullWidth
inputComponent={SelectWrapped}
value={this.state.value}
onChange={this.handleChange}
placeholder="Search your color"
id="react-select-single"
inputProps={{
options: colourOptions
}}
/>
</div>
and then SelectWrapped component implementation should be:
function SelectWrapped(props) {
const { classes, ...other } = props;
return (
<Select
components={{
Option: Option,
DropdownIndicator: ArrowDropDownIcon
}}
styles={customStyles}
isClearable={true}
{...other}
/>
);
}
and I overrides the component Option and DropdownIndicator to make it more material and added customStyles also:
const customStyles = {
control: () => ({
display: "flex",
alignItems: "center",
border: 0,
height: "auto",
background: "transparent",
"&:hover": {
boxShadow: "none"
}
}),
menu: () => ({
backgroundColor: "white",
boxShadow: "1px 2px 6px #888888", // should be changed as material-ui
position: "absolute",
left: 0,
top: `calc(100% + 1px)`,
width: "100%",
zIndex: 2,
maxHeight: ITEM_HEIGHT * 4.5
}),
menuList: () => ({
maxHeight: ITEM_HEIGHT * 4.5,
overflowY: "auto"
})
};
and Option:
class Option extends React.Component {
handleClick = event => {
this.props.selectOption(this.props.data, event);
};
render() {
const { children, isFocused, isSelected, onFocus } = this.props;
console.log(this.props);
return (
<MenuItem
onFocus={onFocus}
selected={isFocused}
onClick={this.handleClick}
component="div"
style={{
fontWeight: isSelected ? 500 : 400
}}
>
{children}
</MenuItem>
);
}
}
please find the example from here: https://codesandbox.io/s/7k82j5j1qx
refer the documentation from react select and you can add more changes if you wish.
hope these will help you.