Material-table: Is it possible to open detailsPanel by default? - javascript

I'm trying to create a subtable of the main React Material-Table.
Everything is working properly as it should work, details panel (subtable) is showing on toggle icon press.
Are there any ways to show it opened by default? I mean to remove the toggle icon and show the detailPanel right from the component render?
Here is how my mat-table looks like (I didn't want to insert the whole component code, cause it will be too much code, full code is in the sandbox):
<MaterialTable
icons={tableIcons}
tableRef={tableRef}
columns={tableColumns}
data={tableData}
onRowClick={(evt, selectedRow) =>
setSelectedRow(selectedRow.tableData.id)
}
title="Remote Data Example"
detailPanel={detailSubtable}
options={{
rowStyle: rowData => ({
backgroundColor:
selectedRow === rowData.tableData.id ? "#EEE" : "#FFF"
})
}}
/>
And a link to the Codesandbox

As per knowledge, there is not any proper way or props to achieve this but you can do native DoM manipulation.
Provide custom Icon in DetailPanel icon with some unique ID like this:
DetailPanel: forwardRef((props, ref) => (
<div id="my-id" style={{ display: "none" }}>
<ChevronRight {...props} ref={ref} />
</div>
)),
Now, On componentDidMount find this element and trigger a click event on it and hide parent node like this
useEffect(() => {
const myToggler = document.getElementById("my-id");
if (!!myToggler) {
myToggler.click();
myToggler.parentNode.style.display = "none";
}
}, []);
here is the working sandbox link forked from yours, let me know if I am missing something.

If you see the source code There is a props called defaultExpanded which should work but there is an open issue which is causing the issue of not opening the panel by default.
To make it work (until the issue is fixed), you can imperatively modify the material-table's component the state in the useEffect
Like this
useEffect(() => {
tableRef.current.state.data = tableRef.current.state.data.map(data => {
console.log(data);
data.tableData.showDetailPanel = tableRef.current.props.detailPanel;
return data;
});
}, []);
Working demo of your code
This solution works for any number of rows/detailsPanel.

Related

Material Table Detail Panel not re-rendering on state change

I'm having issues getting the Detail Panel of Material Table to re-render when there is a change to the tab selection of a Material-UI tab component. What I'm expecting to happen is when I select the second tab in the tab list, the styling and component should re-render to reflect that in the DOM. As of right now that isn't happening. The value property is being updated, but the DOM is never being re-rendered from the value change. The value property I'm passing to the handleChange function is an index. So for 3 tabs, there would be 3 different values (0, 1, 2)
You can see from this example , when you click a subsequent tab in the AppBar, the state is updated and changed automatically. I'm able to effectively change the 'value' property by clicking a different tab, but the Detail Panel is never re-rendered and the first tab is always selected.
This PR had a similar issue but I wasn't able to get any of the answers to work for my need.
import AppBar from '#material-ui/core/AppBar'
import Tabs from '#material-ui/core/Tabs'
import Tab from '#material-ui/core/Tab'
function TableComponent(props) {
const [value, setValue] = React.useState(0)
const handleChange = (event, newValue) => {
setValue(newValue)
}
function getVersionsTabs (rowData) {
const versions = Object.keys(rowData.versions)
var versionList = versions.map(function (name, index) {
const version = rowData.versions[name]
return <Tab key={index} label={version.versionAlias} />
})
return versionList
}
return (
<MaterialTable
...otherProps
detailPanel={
rowData => {
return (
<div>
<AppBar position='static' color='default'>
<Tabs value={value} onChange={handleChange} indicatorColor='primary' textColor='primary'>
{getVersionsTabs(rowData)}
</Tabs>
</AppBar>
</div>
)
}
/>
)
}
Any help is greatly appreciated!

Make multitple controlled material-ui tooltips open one at the time

I have a component where i use a few other componentes. I used to have the problem when a select menu was open, the tooltip overlaps the menu and don't stop showing. Now that i have make the Tooltip 'controlled' when i hover on one component it shows all the tooltips, and when click in one stop appearing (this is what i want but on hover one at the same time). This is how it looks:
I have my tooltip like this outside the function of the component im working on:
function Tooltip(props) {
const classes = tooltipStyles();
return <TooltipBase placement="bottom" classes={classes} {...props} />;
}
And this is how it looks in every component i mannage inside the main component:
<Tooltip title="Estatus" open={openTooltip}>
<div
onMouseEnter={() => {
setOpenTooltip(true);
}}
onMouseLeave={() => {
setOpenTooltip(false);
}}
>
<Chip
small
onIconClicked={null}
label="Por hacer"
avatarProps={{
size: 'extraSmall',
backgroundColor: '#F57C00',
icon: null,
}}
isDropdown
onChipClicked={handleOpen}
withPopover
popoverKey="status"
popoverOpen={chipStatusOpen}
popOverContent={PopupStatus}
onPopoverClose={handleClose}
/>
<PopupFilters
anchorEl={anchorElPopupFilters}
onClose={() => setAnchorElPopupFilters(null)}
/>
</div>
</Tooltip>
These are the functions im using to open/close the tooltips an select/popups
const handleClose = () => {
setChipStatus(false);
setAnchorEl(null);
};
const handleOpen = () => {
setChipStatus(true);
setOpenTooltip(false);
};
And the useStates that i use to make it work
const [chipStatusOpen, setChipStatus] = useState(false);
const [openTooltip, setOpenTooltip] = useState(false);
I want to open one at a time. How can i achieve that? What am i doing wrong?

How to delete or hide multiple components on click with react/react native

https://res.cloudinary.com/catify/image/upload/v1588704903/hcnqjp7okfykkb3az2v3.jpg
Hello im trying to create a proyect of a guessing game, i have multiple components of letters as show in the image, some letters are needed for the answer and some are not, i need a button that when i click it it removes or hides the components that are not needed for the answer, how can i do this with react or react native?
Im saving the letters in a array and then rendering them using Map with a custom component that is styled to look like the photo, im doing it in react native but i think it should be the same in react, any help is welcome, thanks.
return (
<Animated.View style={{flex: 1}}>
{Letters.forEach(element => {
<LetterCard letter={element} />;
})}
<Button
title="eliminar"
onPress={() => {
eliminar;
}}
/>
</Animated.View>
);
You probably need a list in state or somewhere that holds which letters are needed and which aren't, as well as a boolean to determine if you are showing all letters or just your needed letters.
Your button which toggles to show/hide the unneeded letters would simply toggle the neededOnly state.
this.state={
neededLetters = [], //array of needed letters
neededOnly = false,
}
{neededOnly ?
neededLetters.forEach(element => {
<LetterCard letter={element} />;
}) :
Letters.forEach(element => {
<LetterCard letter={element} />;
})}
<Button
title="eliminate"
onPress={() => {
this.setState(prevState => ({
neededOnly: !prevState.neededOnly
}));
/>

How do I close a React Native Modal?

I am currently running into an issue where I can open my react-native modal just fine but once it's open I can't seem to close it. I just started using react-native about three weeks ago so I am extremely new to this.
I have tried implementing solutions that I've found online but nothing seemed to work for me. The opening functionality is great and seems to be working perfectly but when it comes to closing the modal none of the things I've tried have seemed to give the modal that ability. I have not been able to find a solid solution for my exact problem anywhere!
This is how I am opening the modal.
constructor(props) {
super(props);
this.state = {
refreshing: false,
display: false
};
}
triggerModal() {
this.setState(prevState => {
return {
display: true
}
});
}
<View>
<Button onPress = { () => this.triggerModal() } title = "Open Modal"></Button>
<DisplayModal display = { this.state.display } />
</View>
This is the modal itself, I am trying to use a button to close it.
import React from 'react'
import { Modal, View, Image, Text, StyleSheet, Button } from 'react-native';
const DisplayModal = (props) => (
<Modal visible={ props.display } animationType = "slide"
onRequestClose={ this.display }>
<View>
<Button title="close" onPress = { () => !props.display }></Button>
</View>
</Modal>
)
export default DisplayModal;
As my familiarity with react-native is limited, it has been difficult wrapping my head around how some aspects of the framework function... I'm probably just making a dumb mistake somewhere in the code.
I appreciate any help with this problem!
You've almost got it, however we can make a few tweaks to get it working as you want.
As your DisplayModal has no state of its own, the state must be controlled by its parent component. So with that in mind we can do the following. Firstly pass an additional prop called closeDisplay to the DisplayModal. We're going to pass a function that sets the display property in state to false.
<DisplayModal
display={this.state.display}
closeDisplay={() => this.setState({display: false})} // <- we are passing this function
/>
Then in our DisplayModal component we are going to call that function to close the modal. So your DisplayModal component should look like this:
const DisplayModal = (props) => (
<Modal
visible={ props.display }
animationType = "slide"
onRequestClose={ this.display }>
<View>
<Button
title="close"
onPress = { () => props.closeDisplay() }> // <- here we call the function that we passed
</Button>
</View>
</Modal>
)
Notice that the onPress function of the Button in the DisplayModal component, we are calling the function closeDisplay(). This function then sets the state in the parent component, which in turn gets passed back down to the DisplayModal component causing it to hide.

React Native: FlatList filters with extraData won’t refresh

I have a Flatlist which works like a To Do list with a filter for “ToDo” and “Upcoming”. When a user swipes to complete the item, it gets hidden from the list by changing a displayIndex attribute. I would like this to reload the list after the swipe or before the user selects “Upcoming”. After reading through other stack overflow answers I have tried adding extraData={this.state} (and creating a this.state.refresh property which changes after every swipe) to the Flatlist and I also ensured that the list items themselves are React.Components and not PureComponents. I have also tried two ways to hide the ListItems, conditionally rendering them and conditionally changing the style to hidden. Still, I am not seeing any change in my Flatlist.
Below is some partial code to see if there are any gotchas I missed:
In the MainScreen.js
async _addCompletion(myItem) {
//Lots of business logic and after it's done the below code activates
await AsyncStorage.setItem(myItem.key, JSON.stringify(myItem));
await this._updateData();
this.setState({ refresh: !this.state.refresh });
}
render() {
const buttons = ['To Do', 'Upcoming'];
const { displayModeIndex } = this.state;
return (
<View>
<ButtonGroup
onPress={this._updateButtonIndex}
buttons={buttons}
selectedIndex={displayModeIndex}
/>
<FlatList
displayMode={this.state.displayModeIndex}
data={this.state.data}
extraData={this.state}
scrollEnabled={this.state.scrollEnabled}
renderItem={({ item }) => (
<MyListItem
myListItem={item}
addCompletion={this._addCompletion}
displayIndex={this.state.displayModeIndex}
setScrollEnabled={this._setScrollEnabled}
navigation={this.props.navigation}
/>
)}
/>
</View>
);
}
In MyListItem.js
_displayMyItem {
//Logic that determines whether to display a myItem based on several factors. I can confirm this works after refreshing.
}
_hideMyItem = () => {
Animated.timing(this.containerHeight, {
toValue: 0,
}).start(() => {
this.setState({ hidden: true });
});
};
render () {
const {myItem} = this.state;
//Other code that determines how the list item looks depending on myItem data.
return (
//I have also tried to return null if this._displayMyItem(this.state.myItem) returns false
<View style={!this._displayMyItem(this.state.myItem) && { display: 'none' }}>
<Swipeable
onPress={this._onPressRow}
setScrollEnabled={this.props.setScrollEnabled}
addCompletion={this.props.addCompletion}
hideMyItem={this._hideMyItem}
myItem={this.state.myItem}
>
//Other JSX Code
</View>
)
}
The Swipeable is a custom component that calls addCompletion after a swipe and _hideMyItem after everything is done. It is not a PureComponent either.
There's a lot going on here, so I've only included code that seems relevant. I can add more if needed. The addCompletion method is a long
would help some captures...
When you swipe the item , it's just empty right?, if it leaves an empty space try this way of conditional rendering , idk if it would work.
in MyListItem.js
render () {
const {myItem} = this.state;
//Other code that determines how the list item looks depending on myItem data.
return (
//I have also tried to return null if this._displayMyItem(this.state.myItem) returns false
{!this.state.hidden?
<View style={!this._displayMyItem(this.state.myItem) && { display: 'none' }}>
<Swipeable
onPress={this._onPressRow}
setScrollEnabled={this.props.setScrollEnabled}
addCompletion={this.props.addCompletion}
hideMyItem={this._hideMyItem}
myItem={this.state.myItem}
>
//Other JSX Code
</View>:null}
)
}
wich checks if this.state.hidden is false , returns the component, else, returns null

Categories