Display all row instead of 3 row - material-ui

Goal:
Display all row in the in table at the same time.
Problem:
It display only 3 row at the same time in the table.
I would like to display all row at the same time without any limitation.
It doesn't work to use "height: '100%'"
Any idea?
Codesandbox:
https://codesandbox.io/s/mkd4dw?file=/demo.tsx
Thank you!
demo.tsx
import * as React from 'react';
import Box from '#mui/material/Box';
import Rating from '#mui/material/Rating';
import {
DataGrid,
GridRenderCellParams,
GridColDef,
useGridApiContext,
} from '#mui/x-data-grid';
function renderRating(params: GridRenderCellParams<number>) {
return <Rating readOnly value={params.value} />;
}
function RatingEditInputCell(props: GridRenderCellParams<number>) {
const { id, value, field } = props;
const apiRef = useGridApiContext();
const handleChange = (event: React.SyntheticEvent, newValue: number | null) => {
apiRef.current.setEditCellValue({ id, field, value: newValue });
};
const handleRef = (element: HTMLSpanElement) => {
if (element) {
const input = element.querySelector<HTMLInputElement>(
`input[value="${value}"]`,
);
input?.focus();
}
};
return (
<Box sx={{ display: 'flex', alignItems: 'center', pr: 2 }}>
<Rating
ref={handleRef}
name="rating"
precision={1}
value={value}
onChange={handleChange}
/>
</Box>
);
}
const renderRatingEditInputCell: GridColDef['renderCell'] = (params) => {
return <RatingEditInputCell {...params} />;
};
export default function CustomEditComponent() {
return (
<div style={{ height: 250, width: '100%' }}>
<DataGrid
rows={rows}
columns={columns}
experimentalFeatures={{ newEditingApi: true }}
/>
</div>
);
}
const columns = [
{
field: 'places',
headerName: 'Places',
width: 120,
},
{
field: 'rating',
headerName: 'Rating',
renderCell: renderRating,
renderEditCell: renderRatingEditInputCell,
editable: true,
width: 180,
type: 'number',
},
];
const rows = [
{ id: 1, places: 'Barcelona', rating: 5 },
{ id: 2, places: 'Rio de Janeiro', rating: 4 },
{ id: 3, places: 'London', rating: 3 },
{ id: 4, places: 'New York', rating: 2 },
];

You need to make use of autoHeight prop supported by the <DataGrid /> component, update your DataGrid component usage to this:
<DataGrid
autoHeight
rows={rows}
columns={columns}
experimentalFeatures={{ newEditingApi: true }}
/>
Reference: https://mui.com/x/react-data-grid/layout/#auto-height

Related

How to properly render a button or icon inside Data Grid column?

i have a Data Grid table, there's a colomn that holds actions (edit and delete):
(Below is my whole code)
import React, { useEffect } from 'react'
import { DataGrid } from '#mui/x-data-grid'
import { useNavigate } from 'react-router-dom'
import EditIcon from '#mui/icons-material/Edit'
import DeleteForeverIcon from '#mui/icons-material/DeleteForever'
import { Button } from '#mui/material'
const rows = [
{
id: 1,
lastName: 'Snow',
firstName: 'Jon',
age: 35,
edit: EditIcon,
delete: `${(<Button variant="text">Text</Button>)}`,
},
]
const Colors = () => {
const columns = [
{ field: 'id', headerName: 'ID', width: 70 },
{ field: 'firstName', headerName: 'First name', width: 130 },
{ field: 'lastName', headerName: 'Last name', width: 130 },
{
field: 'age',
headerName: 'Age',
type: 'number',
width: 90,
},
{ field: 'edit', headerName: 'Edit', width: 150 },
{ field: 'delete', headerName: 'Delete', width: 150 },
]
return (
<div style={{ height: 560, width: '100%' }}>
<DataGrid
sx={{ backgroundColor: 'white' }}
rows={rows}
columns={columns}
pageSize={8}
rowsPerPageOptions={[8]}
checkboxSelection
/>
</div>
)
}
export default Colors
Now my problem is, i would like to use a material icon inside edit column.
I tried by implementing icon directly like this:
const rows = [
{
id: 1,
lastName: 'Snow',
firstName: 'Jon',
age: 35,
edit: EditIcon, //<--
},
]
Or calling a button by this way:
const rows = [
{
id: 1,
lastName: 'Snow',
firstName: 'Jon',
age: 35,
delete: `${(<Button variant="text">Text</Button>)}`, //<--
},
]
Result: i'm getting a render [object object] instead of icon or button.
How to properly render a button or icon inside Data Grid column?
I think you can try doing this. MUI exposes an actions column type that you can pass custom icons and implementations to. If you scroll down a bit on this link you can find a lot of column options.
Actions column
import { GridActionsCellItem, GridRowParams } from "#mui/x-data-grid-pro";
import EditIcon from "#mui/icons-material/Edit";
{
field: "actions",
type: "actions",
align: "left",
headerName: t("actions"),
getActions: (params: GridRowParams) => [
<GridActionsCellItem
key={0}
icon={<EditIcon titleAccess={t("edit")} color="primary" />}
label={t("edit")}
onClick={() => handleEditPressed(params)}
/>,
],
},
I fixed my problem by using renderCell, with this i can render html inside grid data the way i want (i can put button for exemple):
{
field: 'edit',
headerName: 'Edit',
width: 70,
renderCell: (params) => {
return <EditIcon /> //<-- Mui icons should be put this way here.
},
},

Invariant Violation: View config getter callback for component `g` must be a function (received `undefined`)

The whole message is
Invariant Violation: View config getter callback for component `g` must be a function (received `undefined`). Make sure to start component names with a capital letter.
This error is located at:
in g
in VictorySharedEvents (created by Chart)
in RNSVGGroup (created by G)
in G (created by Svg)
in RNSVGSvgView (created by Svg)
in Svg (created by Cchart)
in RCTView (created by View)
in View (created by Cchart)
in Cchart (created by App)
in RCTView (created by View)
in View (created by App)
in App (created by ExpoRoot)
in ExpoRoot
in RCTView (created by View)
in View (created by AppContainer)
in DevAppContainer (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
The funny thing is this code work totally fine in expo snack online but doesn't work on iOS simulator. I
And there's no lower letter 'g' in my code.
so confused.
<Chart.js>
import Svg, { G } from 'react-native-svg';
import { StyleSheet, Text, View } from 'react-native';
import { VictoryBar, VictorySharedEvents, VictoryPie, VictoryLabel } from 'victory-native';
import * as React from 'react';
export default function Chart {
return (
<Svg viewBox="0 0 550 750">
<VictorySharedEvents
events={[{
childName: ["pie", "bar"],
target: "data",
eventHandlers: {
onMouseOver: () => {
return [{
childName: ["pie", "bar"],
mutation: (props) => {
return {
style: Object.assign({}, props.style, {fill: "silver"})
};
}
}];
},
onMouseOut: () => {
return [{
childName: ["pie", "bar"],
mutation: () => {
return null;
}
}];
}
}
}]}
>
<G transform={"translate(150, 220)"}>
<VictoryLabel
x={180}
y={45}
textAnchor="middle"
style={{fontSize: 10}}
text="Co2 Emission per kg"
/>
<VictoryBar name="bar"
width={220}
standalone={false}
style={{
data: {
fill: ({ datum }) => datum.fill,
opacity: ({ datum }) => datum.opacity
},
}}
data={[
{ itemName: "Butter", label: "Butter", amount: 1, emission: 11.92, fill: "#FFAAA6" },
{ itemName: "Beef", label: "Beef", amount: 1, emission: 26.45, fill: "#FFD3B5" },
{ itemName: "Beans", label: "Beans", amount: 1, emission: 0.73, fill: "#A8E6CE" },
{ itemName: "Selfish", label: "Selfish", amount: 1, emission: 4.11, fill: "chocolate"}
]}
x="itemName"
y={(d) => (d.amount * d.emission)}
/>
</G>
<G transform={"translate(110, -45)"}>
<VictoryPie name="pie"
width={250}
standalone={false}
style={{
data: {
fill: ({ datum }) => datum.fill,
opacity: ({ datum }) => datum.opacity
}
}}
data={[
{ itemName: "Butter", label: "Butter", amount: 1, emission: 11.92, fill: "#FFAAA6" },
{ itemName: "Beef", label: "Beef", amount: 1, emission: 26.45, fill: "#FFD3B5" },
{ itemName: "Beans", label: "Beans", amount: 1, emission: 0.73, fill: "#A8E6CE" },
{ itemName: "Selfish", label: "Selfish", amount: 1, emission: 4.11, fill: "chocolate"}
]}
x="itemName"
y={(d) => (d.amount * d.emission)}
/>
</G>
</VictorySharedEvents>
</Svg>
);
}
<App.js>
import { StyleSheet, Text, View } from 'react-native';
import Chart from './Chart';
import * as React from 'react';
export default function App() {
return (
<View style={styles.container}>
<Chart />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});

Search bar in React Native not updating or filtering

I'm trying to set up data filtering by SearchBar from react-native-elements. I'm returning some data from the server in a JSON format so it arrives in this form of an Array of Objects.
This is what I have so far:
export default function AktList() {
const [akt, setAkt] = useState([]);
const [temp, setTemp] = useState([]);
async function request() {
fetch("http://192.168.5.12:5000/aktprikaz", {
method: "get"
})
.then(res => res.json())
.then(res => setAkt(res))
.then(temp => setTemp(akt));
}
useEffect(() => {
request();
}, []);
function Item({ title, selected }) {
return (
<TouchableOpacity
onPress={() => console.log(temp)}
style={[
styles.item,
{ backgroundColor: selected ? "#6e3b6e" : "#f9c2ff" }
]}
>
<Text style={styles.title}>{title}</Text>
</TouchableOpacity>
);
}
function contains(text) {
const newData = temp.filter(item => {
const itemData = {title};
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setAkt(newData);
}
return (
<SafeAreaView style={styles.container}>
<Header />
<SearchBar onChangeText={text => contains(text)} />
<FlatList
data={akt}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
Currently, nor is the text updating nor is it filter anything. I've tried following this tutorial online (tho it is written using classes not functions). What am I doing wrong here?
Check below example which i created using flatlist and TextInput. Items are displayed in the form of a dropdown list when you search items. i think this will help you.
import React, { Component } from 'react';
import { View, Text, FlatList, TextInput, ListItem } from 'react-native';
class FlatListDropDown extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
value: '',
};
this.arrayNew = [
{ name: 'Robert' },
{ name: 'Bryan' },
{ name: 'Vicente' },
{ name: 'Tristan' },
{ name: 'Marie' },
{ name: 'Onni' },
{ name: 'sophie' },
{ name: 'Brad' },
{ name: 'Samual' },
{ name: 'Omur' },
{ name: 'Ower' },
{ name: 'Awery' },
{ name: 'Ann' },
{ name: 'Jhone' },
{ name: 'z' },
{ name: 'bb' },
{ name: 'cc' },
{ name: 'd' },
{ name: 'e' },
{ name: 'f' },
{ name: 'g' },
{ name: 'h' },
{ name: 'i' },
{ name: 'j' },
{ name: 'k' },
{ name: 'l' },
];
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: '100%',
backgroundColor: '#CED0CE',
}}
/>
);
};
searchItems = text => {
const newData = this.arrayNew.filter(item => {
const itemData = `${item.name.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
this.setState({
data: newData,
value: text,
});
};
renderHeader = () => {
return (
<TextInput
style={{ height: 60, borderColor: '#000', borderWidth: 1 }}
placeholder=" Type Here...Key word"
onChangeText={text => this.searchItems(text)}
value={this.state.value}
/>
);
};
render() {
return (
<View
style={{
flex: 1,
padding: 25,
width: '98%',
alignSelf: 'center',
justifyContent: 'center',
}}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<Text style={{ padding: 10 }}>{item.name} </Text>
)}
keyExtractor={item => item.name}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
/>
</View>
);
}
}
export default FlatListDropDown;
Feel free for doubts.

How to pass input value to form onSubmit without using state in component that renders multiple forms?

This is a bit of a longwinded problem and giving me a ton of headache to solve.
I'm making a voting app. On the page there will be a list of polls on which you can vote. Each poll is a form consisting of input radio buttons representing the different options available for that poll.
What I was doing previously was saving the option you choose to component state in this.state.value and then passing it as an argument to an action creator when the form is submitted.
Problem with this approach is that if I click an option of one poll, and then click submit on another poll, I've actually submitted the wrong option to the wrong poll.
Is there a way to pass input value to form onSubmit without storing it in component state?
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as actions from '../../actions';
import Loading from '../Loading';
class MyPolls extends Component {
constructor(props) {
super(props);
this.state = {
skip: 0,
isLoading: true,
isLoadingMore: false,
value: ''
};
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}
componentDidMount() {
this.props.fetchMyPolls(this.state.skip)
.then(() => {
setTimeout(() => {
this.setState({
skip: this.state.skip + 4,
isLoading: false
});
}, 1000);
});
}
sumVotes(acc, cur) {
return acc.votes + cur.votes
}
loadMore(skip) {
this.setState({ isLoadingMore: true });
setTimeout(() => {
this.props.fetchMyPolls(skip)
.then(() => {
const nextSkip = this.state.skip + 4;
this.setState({
skip: nextSkip,
isLoadingMore: false
});
});
}, 1000);
}
handleSubmit(title, e) {
// console.log(e.target);
e.preventDefault();
const vote = {
title,
option: this.state.value
};
console.log(vote)
}
handleChange(event) {
this.setState({ value: event.target.value });
}
renderPolls() {
return this.props.polls.map(poll => {
return (
<div
className='card'
key={poll._id}
style={{ width: '350px', height: '400px' }}>
<div className='card-content'>
<span className='card-title'>{poll.title}</span>
<p>
Total votes: {poll.options.reduce((acc, cur) => { return acc + cur.votes }, 0)}
</p>
<form onSubmit={e => this.handleSubmit(poll.title, e)}>
{poll.options.map(option => {
return (
<p key={option._id}>
<input
name={poll.title}
className='with-gap'
type='radio'
id={option._id}
value={option.option}
onChange={this.handleChange}
/>
<label htmlFor={option._id}>
{option.option}
</label>
</p>
)
})}
<button
type='text'
className='activator teal btn waves-effect waves-light'
style={{
position: 'absolute',
bottom: '10%',
transform: 'translateX(-50%)'
}}
>
Submit
<i className='material-icons right'>
send
</i>
</button>
</form>
</div>
<div className='card-reveal'>
<span className='card-title'>{poll.title}
<i className='material-icons right'>close</i>
</span>
<p>
dsfasfasdf
</p>
</div>
</div>
)
})
}
render() {
return (
<div className='center-align container'>
<h2>My Polls</h2>
{this.state.isLoading ? <Loading size='big' /> :
<div
style={{
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-evenly',
alignItems: 'center',
alignContent: 'center'
}}>
{this.renderPolls()}
</div>}
<div className='row'>
{this.state.isLoadingMore ? <Loading size='small' /> :
<button
className='btn red lighten-2 wave-effect waves-light' onClick={() => this.loadMore(this.state.skip)}>
Load More
</button>}
</div>
</div>
);
}
}
function mapStateToProps({ polls }) {
return { polls }
}
export default connect(mapStateToProps, actions)(MyPolls);
App demo: https://voting-app-drhectapus.herokuapp.com/
(use riverfish#gmail.com and password 123 to login)
Github repo: https://github.com/drhectapus/voting-app
I'm open to any suggestions. Thanks!
The more "React'ish" pattern would be to break it down to more components.
a Poll is a component, a PollOption could be a component as well.
Where each can handle the state internally.
This will allow you to keep global state in your App or some other state manager like redux that will hold all of your polls and each can reference to the selected option (id).
Another thing worth pointing, is that you tend to pass a new function reference on each render call.
For example:
onSubmit={e => this.handleSubmit(poll.title, e)}
This is considered as bad practice because you can interfere with the Reconciliation and The Diffing Algorithm of react.
When you break it down to components that each can fire back a callback with its
props, then you don't need to pass the handler this way.
Here is a small example with your data:
const pollsFromServer = [
{
_id: "5a0d308a70f4b10014994490",
title: "Cat or Dog",
_user: "59f21388843e737de3738a3a",
__v: 0,
dateCreated: "2017-11-16T06:30:34.855Z",
options: [
{ option: "Cat", _id: "5a0d308a70f4b10014994492", votes: 0 },
{ option: "Dog", _id: "5a0d308a70f4b10014994491", votes: 0 }
]
},
{
_id: "5a0c7941e655c22b8cce43d7",
title: "Blonde or Brunette?",
_user: "59f21388843e737de3738a3a",
__v: 0,
dateCreated: "2017-11-15T17:28:33.909Z",
options: [
{ option: "Blonde", _id: "5a0c7941e655c22b8cce43d9", votes: 0 },
{ option: "Brunette", _id: "5a0c7941e655c22b8cce43d8", votes: 0 }
]
},
{
_id: "5a0c7924e655c22b8cce43d4",
title: "Coke or Pepsi",
_user: "59f21388843e737de3738a3a",
__v: 0,
dateCreated: "2017-11-15T17:28:04.119Z",
options: [
{ option: "Coke", _id: "5a0c7924e655c22b8cce43d6", votes: 0 },
{ option: "Pepsi", _id: "5a0c7924e655c22b8cce43d5", votes: 0 }
]
},
{
_id: "5a0c78c2e655c22b8cce43d0",
title: "Favourite german car?",
_user: "59f21388843e737de3738a3a",
__v: 0,
dateCreated: "2017-11-15T17:26:26.724Z",
options: [
{ option: "BMW", _id: "5a0c78c2e655c22b8cce43d3", votes: 0 },
{ option: "Mercedes", _id: "5a0c78c2e655c22b8cce43d2", votes: 0 },
{ option: "Audi", _id: "5a0c78c2e655c22b8cce43d1", votes: 0 }
]
}
];
class Poll extends React.Component {
onSubmit = optionId => {
const { pollId, onSubmit } = this.props;
onSubmit(pollId, optionId);
};
render() {
const { title, options, selectedOption } = this.props;
return (
<div>
<h3>{title}</h3>
<ul>
{options.map((o, i) => {
return (
<PollOption
isSelected={selectedOption === o._id}
onClick={this.onSubmit}
name={o.option}
optionId={o._id}
/>
);
})}
</ul>
</div>
);
}
}
class PollOption extends React.Component {
onClick = () => {
const { optionId, onClick } = this.props;
onClick(optionId);
};
render() {
const { name, isSelected } = this.props;
const selectedClass = isSelected ? "selected" : '';
return (
<li
className={`poll-option ${selectedClass}`}
onClick={this.onClick}
>
{name}
</li>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
polls: pollsFromServer,
submittedPolls: []
};
}
onPollSubmit = (pollId, optionId) => {
this.setState({
submittedPolls: {
...this.state.submittedPolls,
[pollId]: optionId
}
});
};
render() {
const { polls, submittedPolls } = this.state;
return (
<div>
{polls.map((p, i) => {
const selectedPoll = submittedPolls[p._id];
return (
<Poll
selectedOption={selectedPoll}
pollId={p._id}
onSubmit={this.onPollSubmit}
title={p.title}
options={p.options}
/>
);
})}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
.poll-option{
cursor: pointer;
display: inline-block;
box-shadow: 0 0 1px 1px #333;
padding: 15px;
}
.selected{
background-color: green;
color: #fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Get all the image shots from dibbbler API

I am trying to learn react-native, I just start working on this project two days ago.
I have kind of confusing in how to get the all the image shots from dibbbler API and display it on my android emulator.
This is what I have done,
'use strict';
import React, {
AppRegistry,
Component,
Image,
ListView,
StyleSheet,
View,
} from 'react-native';
var API_URL = 'https://api.dribbble.com/v1/shots';
class myproject extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
};
}
componentDidMount() {
this.fetchData();
}
fetchData() {
fetch(API_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData.images.treaser),
loaded: true,
});
})
.done();
}
render() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.rendershots}
style={styles.listView}
/>
);
}
rendershots(shots) {
return (
<View style={styles.container}>
<Image
source={{uri: shots.images.treas}}
style={styles.images.treas}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
rightContainer: {
flex: 1,
},
treas: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
},
});
AppRegistry.registerComponent('myproject', () => myproject);
You need to provide credentials to retrieve the pictures from dribble.
You can register your app here to get credentials then use them to use the Dribbble API.