Material UI TreeView Filter - javascript

I have a json of files and folders to be rendered as a MUI TreeView component. The treeview works perfectly fine. I need to add a filter to this Treeview component. I am new to React and Javascript. Could you please help me out with this?
The JSON structure for the treeview looks something like this:
const treeViewApiData = {
name: "fl1",
path: "folder 1",
children: [
{
name: "f1",
path: "file 1",
children: [],
isFile: true,
},
{
name: "f2",
path: "file 2",
children: [],
isFile: true,
},
{
name: "f3",
path: "file 3",
children: [],
isFile: true,
},
],
isFile: false,
};
The code for my richObjectTreeView.js looks like this:
export default function RichObjectTreeView(props) {
const dispatch = useDispatch();
const handleOnItemClick = (event, nodeIds) => {
// Displays the node clicked onto the dashboard if it is a file.
}
};
const renderTree = (nodes) => {
if (!nodes || nodes.length === 0) {
return null;
}
return (
<TreeItem key={nodes.path} nodeId={nodes.path} label={nodes.name}>
{Array.isArray(nodes.children)
? nodes.children.map((node) => renderTree(node))
: null}
</TreeItem>
);
};
return props.treeViewApiData ? (
<TreeView
aria-label="rich object"
defaultCollapseIcon={
<>
<ExpandMoreIcon />
<FolderOpenIcon sx={{ marginRight: "12px" }} />
</>
}
defaultExpanded={["root"]}
defaultExpandIcon={
<>
<ChevronRightIcon />
<FolderIcon sx={{ marginRight: "12px" }} />
</>
}
defaultEndIcon={<ArticleIcon />}
sx={{ height: 110, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
onNodeFocus={handleOnItemClick}
>
{renderTree(props.treeViewApiData)}
</TreeView>
) : (
<CircularProgress sx={{ marginLeft: "100px", marginTop: "100px" }} />
);
}

Related

React MUI-Datatables get row id

I have a table that renders two buttons, delete and edit row.
On both of them I need to access the row Id.
I tried to use customBodyRender but it did not work, i have only the dataIndex and the rowIndex, but what I need is the actual row object value.
Updated question with the code
const columns = [
{
name: "id",
label: "Id",
options: {
display: false
}
},
{
name: "name",
label: "Name",
},
{
name: "Actions",
options: {
filter: false,
sort: false,
empty: true,
customBodyRender: (dataIndex, rowIndex) => {
return (
<>
<IconButton aria-label="edit" onClick={() => {
alert(dataIndex + " - " + rowIndex)
}}>
<EditIcon />
</IconButton>
<IconButton color="primary" aria-label="delete" style={{ marginLeft: "10px" }} onClick={() => {
alert(dataIndex)
}}>
<DeleteIcon />
</IconButton>
</>
);
}
}
}];
This is how MUIDataTable is being used
<MUIDataTable
title={"Lista de Turnos"}
data={shifts}
columns={columns}
options={{
selectableRowsHideCheckboxes: true,
textLabels: {
body: {
noMatch: 'Não foram encontrados registros para serem mostrados',
},
},
}}
/>
You can use customBodyRenderLite instead of customBodyRender
The actual code would be like this if you want to access the actual data object.
import React from "react";
import ReactDOM from "react-dom";
import MUIDataTable from "mui-datatables";
import Button from '#material-ui/core/Button'
function App() {
const data = [
{id:1,name:'wahid'},
{id:2,name:'jamil'},
{id:3,name:'marin'},
];
const columns = [
{
name: "id",
label: "Id",
options: {
display: false
}
},
{
name: "name",
label: "Name",
},
{
name: "Actions",
options: {
filter: false,
sort: false,
customBodyRenderLite: (dataIndex, rowIndex) => {
return (
<Button aria-label="edit" onClick={() => {
alert(data[dataIndex].name)
}}>
Button
</Button>
);
}
},
}
];
return (
<React.Fragment>
<MUIDataTable
title={"ACME Employee list"}
data={data}
columns={columns}
options={{
selectableRowsHideCheckboxes: true,
textLabels: {
body: {
noMatch: 'Não foram encontrados registros para serem mostrados',
},
},
}}
/>
</React.Fragment>
);
}
ReactDOM.render(<App />, document.getElementById("root"));

Can't Scroll SectionList Until Last Item Because Out of Viewport

I have issue with a long sectionlist that went off outside of viewport, how can I make it work normally? I have tried using flexShrink:1 but it didn't work. other solution I have tried is using <ScrollView> but it giving me error VirtualizedLists should never be nested inside plain ScrollViews with the same orientation because it can break windowing and other functionality - use another VirtualizedList-backed container instead. I really need help for this issue, how to make the SectionList stay inside and work normally? here is some example code I have tried
App.js
import React, { Component } from "react";
import { View, Text } from "react-native";
import AnotherJS from "./AnotherJS";
export default class App extends Component {
render(){
return(
<View style={{backgroundColor:"#5273B7", flex:1, padding:10}}>
<View style={{backgroundColor:"#ff0000", borderTopLeftRadius:10, borderTopRightRadius:10, padding: 10}}>
<View style={{backgroundColor:"#ffffff", borderRadius:10}}>
<Text>Picker Here</Text>
</View>
</View>
<View style={{backgroundColor:"#00ff00", flex:1, borderBottomLeftRadius:10, borderBottomRightRadius:10, padding:10}}>
<View style={{flexShrink:1}}>
<AnotherJS/>
</View>
</View>
</View>
)
}
}
AnotherJS.js
import React, { Component } from "react";
import {View, Text, SectionList } from "react-native";
import Accordion from "react-native-collapsible/Accordion";
const dataArray = [
{ title: "Info 1",
content: [
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
] },
{ title: "Info 2",
content: [
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
] },
{ title: "info 3",
content: [
{ title: "1", data: ["1"]},
{ title: "2", data: ["2"]},
] }
];
const Item = ({ title }) => (
<View>
<Text>{title}</Text>
</View>
);
export default class AnotherJS extends Component {
state = {
activeSections: [0],
};
_renderHeader = (section) => {
return(
<View style={{
flexDirection: "row",
padding: 10,
justifyContent: "space-between",
alignItems: "center" ,
backgroundColor: "#A9DAD6" }}>
<Text style={{ fontWeight: "600" }}>{section.title}</Text>
</View>
);
};
_renderContent = (section) => {
return(
<SectionList
sections={section.content}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text>{title}</Text>
)}
/>
);
};
_updateSections = (activeSections) => {
this.setState({ activeSections });
};
render() {
return (
<View style={{flexShrink:1}}>
<Accordion
sections = {dataArray}
activeSections = {this.state.activeSections}
renderHeader = {this._renderHeader}
renderContent = {this._renderContent}
onChange = {this._updateSections}
/>
</View>
);
}
}
Try to wrap your list component in a container.
_renderContent = (section) => {
return(
<ListContainer style={{flex: 1}}> // you can add borders for clarity
<SectionList
sections={section.content}
keyExtractor={(item, index) => item + index}
renderItem={({ item }) => <Item title={item} />}
renderSectionHeader={({ section: { title } }) => (
<Text>{title}</Text>
<ListContainer/>
)}
/>
);
};
ListContainer code:
const ListContainer = styled.View`
flex: 1;
`;

React Native onPress button in FlatList

Maybe it is a noob problem but I can not make an onPress for FlatList in react native made of an items of array in the separate file popularData and categoriesData. In popularData I have an array with information of it is selected or not boolean type, I just want to get this info of the array, and put it to onPress method to change the selected to true or false if its pressed and change it backgroundColor to another, and further to fetch that data and get it to some variable. Can you please help me ? I've tried with handleClick, navigation but still can't reach that what I want These are the codes:
File 1 with the info in array:
const popularData = [
{
id: '1',
image: require('../images/pizza1.png'),
title: 'Salami Pizza',
weight: '600 gr',
rating: '5.0',
cena: '26,99 zł',
rozmiarNazwa: 'Średnia',
rozmiarNumer: '42 cm',
ciasto: 'Cienkie',
czasDostawy: '~30 min',
skladniki: [
{
id: '0',
name: 'Sos pomidorowy',
image: require('../images/skladniki/sosczerwony.png'),
selected: true,
},
{
id: '1',
name: 'Ser',
image: require('../images/skladniki/ser.png'),
selected: true,
},
{
id: '2',
name: 'Salami',
image: require('../images/skladniki/salamenapoli.png'),
selected: true,
},
{
id: '3',
name: 'Oliwki zielone',
image: require('../images/skladniki/zieloneoliwki.png'),
selected: true,
},
{
id: '5',
name: 'Pieczarki',
image: require('../images/skladniki/pieczarki.png'),
selected: false,
},
{
id: '6',
name: 'Tabasco Habanero',
image: require('../images/skladniki/tabascobordowe.png'),
selected: false,
},
],
},
export default popularData;
ANOTHER FILE the app screen
const renderSkladnikiItem = ({ item }) => {
return (
<View style={[styles.skladnikiItemWrapper, {
backgroundColor: item.selected ? colors.glowny : colors.tlo,
marginLeft: item.id === '0' ? 20 : 5,
} ]}>
<Image source={item.image} style={styles.skladnikImage} />
</View>
);
};
{/* Skladniki */}
<View style={styles.skladnikiWrapper}>
<Text style={styles.skladnikiTytul}>Składniki</Text>
<View style={styles.sklanikiListaWrapper}>
<FlatList
data={item.skladniki}
renderItem={renderSkladnikiItem}
keyExtractor={(item) => item.id}
horizontal={true}
showsHorizontalScrollIndicator={false}
decelerationRate="normal"
/>
</View>
</View>
You can enclose your View in TouchableOpacity or TouchbaleHighlight to apply onPress on.
const renderSkladnikiItem = ({ item }) => {
return (
<TouchableHighlight
key={item.key}
onPress={() => onPress(item)}
>
<View style={[styles.skladnikiItemWrapper, {
backgroundColor: item.selected ? colors.glowny : colors.tlo,
marginLeft: item.id === '0' ? 20 : 5,
} ]}>
<Image source={item.image} style={styles.skladnikImage} />
</View>
</TouchableHighlight>
);
};

converting antd table data into hooks

React beginner here, i'm currently learning Reactjs, since everybody is saying React hooks is easier to start with, so i started with hooks, but everywhere is mainly react with classes, here in this example (antd table) it is coded using classes, if i have understood it currently, i should put 'searchText:'',searchedColumn:'',' into useState, and dont need useEffect ? since there is no componentdimount or udpate .. ? just for learning want to change this class code into Hooks, sory for mistakes because english is not my mother language:
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Table, Input, Button, Space } from 'antd';
import Highlighter from 'react-highlight-words';
import { SearchOutlined } from '#ant-design/icons';
const data = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
},
{
key: '2',
name: 'Joe Black',
age: 42,
address: 'London No. 1 Lake Park',
},
{
key: '3',
name: 'Jim Green',
age: 32,
address: 'Sidney No. 1 Lake Park',
},
{
key: '4',
name: 'Jim Red',
age: 32,
address: 'London No. 2 Lake Park',
},
];
class App extends React.Component {
state = {
searchText: '',
searchedColumn: '',
};
getColumnSearchProps = dataIndex => ({
filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => (
<div style={{ padding: 8 }}>
<Input
ref={node => {
this.searchInput = node;
}}
placeholder={`Search ${dataIndex}`}
value={selectedKeys[0]}
onChange={e => setSelectedKeys(e.target.value ? [e.target.value] : [])}
onPressEnter={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
style={{ width: 188, marginBottom: 8, display: 'block' }}
/>
<Space>
<Button
type="primary"
onClick={() => this.handleSearch(selectedKeys, confirm, dataIndex)}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button onClick={() => this.handleReset(clearFilters)} size="small" style={{ width: 90 }}>
Reset
</Button>
<Button
type="link"
size="small"
onClick={() => {
confirm({ closeDropdown: false });
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex,
});
}}
>
Filter
</Button>
</Space>
</div>
),
filterIcon: filtered => <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />,
onFilter: (value, record) =>
record[dataIndex]
? record[dataIndex].toString().toLowerCase().includes(value.toLowerCase())
: '',
onFilterDropdownVisibleChange: visible => {
if (visible) {
setTimeout(() => this.searchInput.select(), 100);
}
},
render: text =>
this.state.searchedColumn === dataIndex ? (
<Highlighter
highlightStyle={{ backgroundColor: '#ffc069', padding: 0 }}
searchWords={[this.state.searchText]}
autoEscape
textToHighlight={text ? text.toString() : ''}
/>
) : (
text
),
});
handleSearch = (selectedKeys, confirm, dataIndex) => {
confirm();
this.setState({
searchText: selectedKeys[0],
searchedColumn: dataIndex,
});
};
handleReset = clearFilters => {
clearFilters();
this.setState({ searchText: '' });
};
render() {
const columns = [
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '30%',
...this.getColumnSearchProps('name'),
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '20%',
...this.getColumnSearchProps('age'),
},
{
title: 'Address',
dataIndex: 'address',
key: 'address',
...this.getColumnSearchProps('address'),
},
];
return <Table columns={columns} dataSource={data} />;
}
}
ReactDOM.render(<App />, document.getElementById('container'));
Code can also be found here: https://codesandbox.io/s/lq2it?file=/package.json
Yes, searchText and searchedColumn are states and should be declared with useState like so:
const [searchText, updateSearchText] = useState('default_state');
const [searchedColumn, updateSearchedColumn] = useState('default_state');
updateSearchText(some_value) is the equivalent for
this.setState({
searchText : some_value
})
and updateSearchedColumn is the same said above but for the state: searchedColumn

How to identify a certain object id of an array to change the state of an element in the same object?

I am trying to identify a specific panel in an array when it is expanded and be able to connect that panel's id to the button, as well as disable the button if no panel is expanded or more than 1 panel is expanded. For whatever reason, it's not taking in the id at all. Also, I am having problems with how to disable the button correctly.
export default class WorkoutList extends Component {
constructor(props) {
super(props);
this.state = {
workoutlist: [
{
id: uuid.v4(),
name: 'Leg Day',
date: '08/09/19',
duration: 60,
exerciselist: [
{
id: uuid.v4(),
exerciseName: 'Squats',
numberOfSets: 3,
reps: 12,
weight: 135,
},
{
id: uuid.v4(),
exerciseName: 'Leg press',
numberOfSets: 3,
reps: 10,
weight: 150,
},
{
id: uuid.v4(),
exerciseName: 'Lunges',
numberOfSets: 4,
reps: 12,
},
],
selected: false,
},
{
id: uuid.v4(),
name: 'Arm Day',
date: '08/10/19',
duration: 90,
exerciselist: [
{
id: uuid.v4(),
exerciseName: 'Bench Press',
numberOfSets: 5,
reps: 5,
weight: 225,
},
{
id: uuid.v4(),
exerciseName: 'Chest Flies',
numberOfSets: 3,
reps: 10,
weight: 50,
},
{
id: uuid.v4(),
exerciseName: 'Tricep Extensions',
numberOfSets: 4,
reps: 12,
weight: 70,
},
],
selected: false,
},
{
id: uuid.v4(),
name: 'Running',
date: '08/11/19',
duration: 40,
exerciselist: [],
selected: false,
},
],
disabled: false
}
this.handleSelectedPanel = this.handleSelectedPanel.bind(this);
this.handleButton = this.handleButton.bind(this);
}
handleSelectedPanel(id) {
const { workoutlist } = this.state;
this.setState({
workoutlist: workoutlist.map(workout => {
if (workout.id === id) {
workout.selected = !workout.selected
}
return workout;
})
})
}
handleButton(){
const { workoutlist, disabled } = this.state;
let count = 0;
workoutlist.map((workout) => {
if(workout.selected === true) {
count = count + 1;
}
return count;
})
if (count !== 1) {
this.setState({
disabled: true
})
} else {
this.setState({
disabled: false
})
}
return disabled;
}
render() {
const { workoutlist } = this.state;
return (
<div>
<CssBaseline />
<ClientMenuBar title="My Workouts" />
<div style={styles.workoutlist}>
<Paper style={styles.paper} elevation={0}>
{workoutlist.map((workout) => (
<WorkoutItem
key={workout.id}
workout={workout}
onSelectedPanel={this.handleSelectedPanel}
/>
))}
</Paper>
<Button
variant="contained"
color="primary"
size="small"
style={styles.button}
disabled={this.handleButton}
>
Start Workout
</Button>
</div>
</div>
)
}
}
export default class WorkoutItem extends Component {
constructor(props){
super(props);
this.handleSelectedPanel = this.handleSelectedPanel.bind(this);
}
handleSelectedPanel(e) {
this.props.onSelectedPanel(e.target.id);
}
render() {
const { id, name, date, duration, exerciselist } = this.props.workout;
return (
<ExpansionPanel style={styles.panel} id={id} onChange={this.handleSelectedPanel}>
<ExpansionPanelSummary>
<Typography variant="button" style={{ width: "33%" }}>
{name}
</Typography>
<Typography variant="button" style={{ width: "33%" }}>
({date})
</Typography>
<Typography align="right" style={{ width: "33%" }}>
~{duration} mins
</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Table size="medium" style={styles.table}>
<TableHead>
<TableRow>
<TableCell padding="none">Name</TableCell>
<TableCell padding="none" align="right"># of sets</TableCell>
<TableCell padding="none" align="right">reps</TableCell>
<TableCell padding="none" align="right">weight</TableCell>
</TableRow>
</TableHead>
<TableBody>
{exerciselist.map((exercise) => (
<ExerciseList
key={exercise.id}
exercise={exercise}
/>
))}
</TableBody>
</Table>
<ExpansionPanelActions disableSpacing style={styles.actionButton}>
<Button color="primary" size="small" disableRipple>
edit
</Button>
</ExpansionPanelActions>
</ExpansionPanelDetails>
</ExpansionPanel>
)
}
}
It doesn't seem to be taking in the id at all, and when i try to disable the button, it throws this error:
Warning: Failed prop type: Invalid prop disabled of type function supplied to ForwardRef(Button), expected boolean.
The warning you are seeing comes from:
<Button
variant="contained"
color="primary"
size="small"
style={styles.button}
disabled={this.handleButton}
>
In the error it says a function is passed to disabled which should be a boolean, so change the prop that disabled takes to be that boolean (rather than the function this.handleButton).
e.target.id doesn't have what you actually want in there (it actually probably isn't a thing). You can use e.target.value to get a value out of something like an input where you want to get something information from the DOM node you are working with but in this case the information isn't something entered and actually something that the component already has in its scope (in the props). So instead of:
handleSelectedPanel(e) {
this.props.onSelectedPanel(e.target.id);
}
do this
handleSelectedPanel(e) {
this.props.onSelectedPanel(this.props.workout.id);
}

Categories