Problem with Select mui and Object value dissapears - node.js

I feel like I am very close to fixing it but when I change select option the selected values disappear. How can I avoid this when using Objects in MUI select?
Code Sandbokx: https://codesandbox.io/s/jovial-pascal-ngpgyh?file=/src/App.js:0-909
import { useState } from "react";
import "./styles.css";
import { TextField, MenuItem } from "#material-ui/core";
export default function App() {
const mainOptions = [
{ id: 1, text: "hello" },
{ id: 2, text: "This is just a test" }
];
function handleFilterChange(e) {
console.log(e.target);
setChosenFilterId(e.target.value);
}
const [chosenFilterId, setChosenFilterId] = useState(0);
return (
<>
<TextField
select
label="Category"
value={mainOptions[chosenFilterId].text}
onChange={(e) => handleFilterChange(e)}
>
{mainOptions.map((option, index) => {
return (
//When i try to change value={option} to value={index} I also get another error
<MenuItem value={option} key={index}>
{option.text}
</MenuItem>
);
})}
</TextField>
</>
);

TextField's value and MenuItem's value couldn't be an Object, and both should be the same kay.
So,
<TextField
select
label="Category"
value={chosenFilterId} // <= here
onChange={(e) => handleFilterChange(e)}
>
{mainOptions.map((option, index) => {
return (
<MenuItem value={option.id} key={index}> {/* <= here */ }
{option.text}
</MenuItem>
);
})}
</TextField>
Demo: https://codesandbox.io/s/immutable-star-ppzgzl?file=/src/App.js

Related

react e commerce fetch category and display error

hi guys and thanks for help
for my last year in university i need to build some project to graduate with mern stack so i chose to make an e-commerce website everything was working fine until i start to create a component for the category of each product : when i click to an category to display all product related to that category the page always display to me empty i dont know how to fix it the categrory button dont fetch for me the products that it is related to an specific category
this is the component of category list
import React from 'react';
import { LinkContainer } from 'react-router-bootstrap';
import { Nav, NavItem } from 'react-bootstrap';
import { useDispatch, useSelector } from 'react-redux';
import SearchBox from './SearchBox';
import Product from './Product';
import HomeScreen from '../screens/HomeScreen';
const CategoryList = ({list}) => {
const productList = useSelector((state) => state.productList);
const { loading, error, products, page, pages } = productList;
{products.map((product) => {
return (
console.log(product.category+"this one ")
)
})}
return (
<Nav className='mb-4'>
{products.map((product) => {
const {category} = product
console.log(category+"this is category")
return (
<Nav.Item>
<a onClick={<SearchBox match={product.category}/>}>{category}</a>
<LinkContainer
to={`/search/${category}`}>
<Nav.Link>{product.category}</Nav.Link>
</LinkContainer>
</Nav.Item>
)
})}
{/* add more categories as needed */}
</Nav>
);
};
export default CategoryList;
and this is the component of the Home screen :
import React, { useEffect } from 'react'
import { Link } from 'react-router-dom'
import { useDispatch, useSelector } from 'react-redux'
import { Row, Col } from 'react-bootstrap'
import Product from '../components/Product'
import Message from '../components/Message'
import Loader from '../components/Loader'
import Paginate from '../components/Paginate'
import ProductCarousel from '../components/ProductCarousel'
import Meta from '../components/Meta'
import { listProducts } from '../actions/productActions'
import CategoryList from '../components/CategoryList'
const HomeScreen = ({ match }) => {
const keyword = match.params.keyword
const pageNumber = match.params.pageNumber || 1
const dispatch = useDispatch()
const productList = useSelector((state) => state.productList)
const { loading, error, products, page, pages } = productList
{products.map((product) => {
return (
console.log(product.category)
)
})}
useEffect(() => {
dispatch(listProducts(keyword, pageNumber))
}, [dispatch, keyword, pageNumber])
return (
<>
<Meta />
{!keyword ? (
<ProductCarousel />
) : (
<Link to='/' className='btn btn-light'>
Go Back
</Link>
)}
<h1>Latest Products</h1>
<CategoryList/>
{loading ? (
<Loader />
) : error ? (
<Message variant='danger'>{error}</Message>
) : (
<>
<Row>
{products.map((product) => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>
<Paginate
pages={pages}
page={page}
keyword={keyword ? keyword : ''}
/>
</>
)}
</>
)
}
export default HomeScreen

'DELETE' 'Title' does not delete the 'title' row 'sub-title, count'; but shows 'title' row again with the 'totalcount' - ReactJS

I have a table which contains Title, Sub-Title and TotalCount. sub-title is the child of title. So, in the collection of title, objectId of sub-title is saved in the database. Below is the screenshot of the table.
Title contains Kilo , Test and Grams with it's respective sub-title and totalcount
What happens is, suppose I delete row Title with Test. Once hit delete, I should get records that are Kilo and Grams. But I don't get that. In fact, I get row with Test with deleted sub-title as blank and the totalcount which adds up all the previous count and displays 4.
The same problem arises when I delete Title Grams.
Below is the code related to the issue
mainPage.js
import React,{ Component } from 'react';
import { connect } from 'react-redux';
import Grid from '#material-ui/core/Grid';
import TabPanel from '../../utils/TabPanel';
import { mainStructure, deleteDbData } from './actions';
import TitleSubtitleTable from './titlesubtitletable';
class MainPage extends Component {
constructor() {
super();
this.state = { filter: {} };
}
componentDidMount() {
this.getData();
}
getData = async () => {
let data = {
data: {
title:
this.state.filter && this.state.filter.title
? this.filter.title
: null,
subtitle:
this.state.filter && this.state.filter.subtitle
? this.state.filter.subtitle
: null,
},
};
await this.props.mainStructure(data);
};
deleteData = async (title) => {
let payload = {
type: title.type,
id: title._id,
};
await this.props.deleteDbData(payload);
await this.getData();
};
render() {
return (
<div>
<Grid>
<TabPanel>
{this.props.structure.tablestructure.data ? (
<TitleSubtitleTable
records={this.props.structure.tablestructure.data}
totalCount={this.props.structure.tablestructure.totalCount}
handleDelete={this.deleteData}
/>
) : null}
</TabPanel>
</Grid>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
structure: state.structure,
};
};
export default connect(mapStateToProps, { mainStructure, deleteDbData })(
MainPage
);
Below is code for titlesubtitletable.js
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import DeleteIcon from '#material-ui/icons/Delete';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
const columns = [
{ id: 'title', label: 'Title' },
{ id: 'delete', label: '' },
{ id: 'subtitle', label: 'Sub-Title' },
{ id: 'count', label: 'Total Count' },
];
function EnhancedTableTitle() {
return (
<TableHead>
<TableRow>
{columns.map((titleCell) => (
<TableCell key={titleCell.id}> {titleCell.label} </TableCell>
))}
</TableRow>
</TableHead>
);
}
export default function EnhancedTable(props) {
return (
<div>
<TableContainer>
<Table>
<EnhancedTableTitle />
<TableBody>
{props.records.map((row, index) => {
return row.children.length > 0 ? (
row.children.map((title) => (
<TableRow key={index}>
<TableCell> {row.name} </TableCell>
<TableCell>
<IconButton onClick={() => props.handleDelete(row)}>
<Avatar>
<DeleteIcon color='action' />
</Avatar>
</IconButton>
</TableCell>
<TableCell align='left' className={classes.tableCellSmall}>
{title.name}
</TableCell>
<TableCell align='left' className={classes.tableCellSmall}>
<IconButton onClick={() => props.handleDelete(title)}>
<Avatar>
<DeleteIcon color='action' />
</Avatar>
</IconButton>
</TableCell>
<TableCell>{title.count}</TableCell>
</TableRow>
))
) : (
<TableRow key={index}>
<TableCell>{row.name} </TableCell>
<TableCell>
<IconButton onClick={() => props.handleDelete(row)}>
<Avatar>
<DeleteIcon color='action' />
</Avatar>
</IconButton>
</TableCell>
<TableCell></TableCell>
<TableCell></TableCell>
<TableCell>{row.count}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</TableContainer>
</div>
);
}
Brief Explanation: I do not want the deleted record to be seen again when I try to delete Title. If 3 different titles, and delete one title, the result should be 2 titles and not the 3 which adds up and shows totalcount
I don't know where I am going wrong. Really need help to figure out the problem. Thank you!!

Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. With HOC

I've implemented an HOC that hide a component if the user hasn't subscribed,after that, i got that red error that I can't understand.
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of from render. Or maybe you meant to call this function rather than return it.
Here is the HOC :
const withSubscription = <P extends object>(
BaseComponent: ComponentType<P>,
pack: Pack,
): ((props: P) => ReactElement | null) => (props: P): null | ReactElement => {
const { subscription } = useSubscription();
const subscriptionIndex = useMemo(() => subscription?.findIndex((subscriptionPack) => subscriptionPack === pack), [pack]);
if (subscriptionIndex === -1) {
return null;
}
return <BaseComponent {...props} />;
};
I've applied the HOC to a button :
const Button: FC = (props) => {
return (
<TouchableOpacity
style={[
styles.cartButtonContainer,
{ backgroundColor: primaryColor },
]}
onPress={handleAddProduct}
>
<Icon
name={"cart-arrow-down"}
materialCom
style={{ marginRight: 0 }}
size={25}
color={secondaryColor}
/>
</TouchableOpacity>
);
};
export default withSubscription(CartButton, Pack.CLICK_COLLECT);
And here is how I call it :
return (
<Button onPress={...}/>
)
There is something i'm doing wrong ?

How to handle 'Enter' on Input in React

I have a form in React, with an Input and Search Button. Currently the Search Button is doing performing the search. I want if a user presses the Enter in Field, Search Button is triggered.
Currently Enter just clears the Input Field. I have onClickhandler on Search Button. I want to apply same handler on Keydown or Keypress event on Field as well.
Below is my code:
import React, {Component} from 'react';
import {FormattedMessage} from 'react-intl';
import {FormField, Form} from 'digitalexp-common-components-l9';
import Input from 'digitalexp-common-components-l9/lib/form-field/Input';
import messages from 'digitalexp-select-additional-charges-retail-module-l9/src/widget/SelectAdditionalCharges.i18n';
const {FormContainer} = Form;
#FormContainer({hasDefaults: true})
export default class SelectAdditionalChargesSearchBoxView extends Component {
constructor(props) {
super(props);
this.handleSearchClick = this.handleSearchClick.bind(this);
this.handleClearClick = this.handleClearClick.bind(this);
}
componentWillMount() {
this.props.initializeFormValues({searchkey: this.props.searchBy});
}
handleClearClick() {
const {updateField} = this.props;
updateField({name: 'searchkey', value: ''}).then(() => this.props.handleSearchBy({searchkey: ''}));
}
handleSearchClick(e) {
const {handleSubmit, handleSearchBy} = this.props;
e.preventDefault();
handleSubmit(handleSearchBy);
}
render() {
const {Field} = FormField;
return (
<div className="ds-search-panel">
<div className="ds-search-panel__header">
<FormattedMessage {...messages.SelectSearchAdditionalCharges} />
</div>
<form
className="ds-search-panel__footer"
autoComplete="off"
onSubmit={this.handleSearchClick}>
<span className="ds-search-panel__footer--names">
<FormattedMessage {...messages.nameLabel} />
</span>
<span className="ds-search-panel__footer--textfields">
<Field
Component={Input}
name="searchkey"
autoComplete="off"
config={{rowLabel: true}}
/>
</span>
<span className="ds-search-panel__footer--search">
<button className="ds-btn ds-btn--secondary ds-btn--searches" onClick={this.handleClearClick}>
<span className="ds-btn--span">
<FormattedMessage {...messages.clearButtonText} />
</span>
</button>
<button className="ds-btn ds-btn--primary ds-btn--searches" onClick={this.handleSearchClick}>
<span className="ds-btn--span">
<FormattedMessage {...messages.searchButtonText} />
</span>
</button>
</span>
</form>
</div>
);
}
}
And below is the Input.js class:
import React from 'react';
import classNames from 'classnames';
const Input = (props) => {
const {
input, label, type = 'text', usePlaceholder, meta: {error}, displayInlineError = true,
fieldIconClassName, showCloseButton, fieldIconEventListener, clearField
} = props;
let {fieldClassName = 'ds-text'} = props;
const {name, placeholder} = input;
fieldClassName = classNames('ds-form__input', {
[fieldClassName]: fieldClassName
});
let fieldIconProps = {
className: classNames({
'ds-form__icon': true,
[fieldIconClassName]: fieldIconClassName
})
};
if (fieldIconEventListener) {
fieldIconProps = {
...fieldIconProps,
onClick: fieldIconEventListener
};
}
return (
<div className="ds-form__input--wrapper">
<input
id={name}
{...input}
placeholder={usePlaceholder ? placeholder || label : ''}
type={type}
className={fieldClassName}
/>
{showCloseButton && <button className="ds-form__icon ds-form__icon--close" onMouseDown={clearField} />}
{fieldIconClassName && <div {...fieldIconProps} />}
{(error && displayInlineError) && <div className="ds-notification__error--text">{error}</div>}
</div>
);
};
export default Input;
Could anyone help?
You can just attach onKeyDown or onKeyUp handler to Field
handleKeyPress (e) {
// This is perfectly safe in react, it correctly detect the keys
if(event.key == 'Enter'){
this.handleSearchClick(e)
}
}
<Field onKeyDown={this.handleKeyPress}

React Virtualized - Table Example - How do I make it work?

I've been struggling to make this react virtualized table example work & seriously starting to doubt my sanity. I've created a react app and I'm just trying to render the example table inside App.js with this:
class App extends Component {
render() {
var data = [1,2,3,4,5,6,7,8,9,10];
return (
<TableExample
list={data}
/>
);
}
}
React keeps saying list isn't defined - it seems obvious I'm not getting the data into the component the right way. I haven't been able to understand the example code, what props need to be passed in and what they should be named. Sorry for the stupid question but I've been stuck forever not knowing where else to find an answer. The table example code is below:
/** #flow */
import Immutable from 'immutable';
import PropTypes from 'prop-types';
import * as React from 'react';
import {
ContentBox,
ContentBoxHeader,
ContentBoxParagraph,
} from '../demo/ContentBox';
import {LabeledInput, InputRow} from '../demo/LabeledInput';
import AutoSizer from '../AutoSizer';
import Column from './Column';
import Table from './Table';
import SortDirection from './SortDirection';
import SortIndicator from './SortIndicator';
import styles from './Table.example.css';
export default class TableExample extends React.PureComponent {
static contextTypes = {
list: PropTypes.instanceOf(Immutable.List).isRequired,
};
constructor(props, context) {
super(props, context);
const sortBy = 'index';
const sortDirection = SortDirection.ASC;
const sortedList = this._sortList({sortBy, sortDirection});
this.state = {
disableHeader: false,
headerHeight: 30,
height: 270,
hideIndexRow: false,
overscanRowCount: 10,
rowHeight: 40,
rowCount: 1000,
scrollToIndex: undefined,
sortBy,
sortDirection,
sortedList,
useDynamicRowHeight: false,
};
this._getRowHeight = this._getRowHeight.bind(this);
this._headerRenderer = this._headerRenderer.bind(this);
this._noRowsRenderer = this._noRowsRenderer.bind(this);
this._onRowCountChange = this._onRowCountChange.bind(this);
this._onScrollToRowChange = this._onScrollToRowChange.bind(this);
this._rowClassName = this._rowClassName.bind(this);
this._sort = this._sort.bind(this);
}
render() {
const {
disableHeader,
headerHeight,
height,
hideIndexRow,
overscanRowCount,
rowHeight,
rowCount,
scrollToIndex,
sortBy,
sortDirection,
sortedList,
useDynamicRowHeight,
} = this.state;
const rowGetter = ({index}) => this._getDatum(sortedList, index);
return (
<ContentBox>
<ContentBoxHeader
text="Table"
sourceLink="https://github.com/bvaughn/react-virtualized/blob/master/source/Table/Table.example.js"
docsLink="https://github.com/bvaughn/react-virtualized/blob/master/docs/Table.md"
/>
<ContentBoxParagraph>
The table layout below is created with flexboxes. This allows it to
have a fixed header and scrollable body content. It also makes use of{' '}
<code>Grid</code> for windowing table content so that large lists are
rendered efficiently. Adjust its configurable properties below to see
how it reacts.
</ContentBoxParagraph>
<ContentBoxParagraph>
<label className={styles.checkboxLabel}>
<input
aria-label="Use dynamic row heights?"
checked={useDynamicRowHeight}
className={styles.checkbox}
type="checkbox"
onChange={event =>
this._updateUseDynamicRowHeight(event.target.checked)
}
/>
Use dynamic row heights?
</label>
<label className={styles.checkboxLabel}>
<input
aria-label="Hide index?"
checked={hideIndexRow}
className={styles.checkbox}
type="checkbox"
onChange={event =>
this.setState({hideIndexRow: event.target.checked})
}
/>
Hide index?
</label>
<label className={styles.checkboxLabel}>
<input
aria-label="Hide header?"
checked={disableHeader}
className={styles.checkbox}
type="checkbox"
onChange={event =>
this.setState({disableHeader: event.target.checked})
}
/>
Hide header?
</label>
</ContentBoxParagraph>
<InputRow>
<LabeledInput
label="Num rows"
name="rowCount"
onChange={this._onRowCountChange}
value={rowCount}
/>
<LabeledInput
label="Scroll to"
name="onScrollToRow"
placeholder="Index..."
onChange={this._onScrollToRowChange}
value={scrollToIndex || ''}
/>
<LabeledInput
label="List height"
name="height"
onChange={event =>
this.setState({height: parseInt(event.target.value, 10) || 1})
}
value={height}
/>
<LabeledInput
disabled={useDynamicRowHeight}
label="Row height"
name="rowHeight"
onChange={event =>
this.setState({
rowHeight: parseInt(event.target.value, 10) || 1,
})
}
value={rowHeight}
/>
<LabeledInput
label="Header height"
name="headerHeight"
onChange={event =>
this.setState({
headerHeight: parseInt(event.target.value, 10) || 1,
})
}
value={headerHeight}
/>
<LabeledInput
label="Overscan"
name="overscanRowCount"
onChange={event =>
this.setState({
overscanRowCount: parseInt(event.target.value, 10) || 0,
})
}
value={overscanRowCount}
/>
</InputRow>
<div>
<AutoSizer disableHeight>
{({width}) => (
<Table
ref="Table"
disableHeader={disableHeader}
headerClassName={styles.headerColumn}
headerHeight={headerHeight}
height={height}
noRowsRenderer={this._noRowsRenderer}
overscanRowCount={overscanRowCount}
rowClassName={this._rowClassName}
rowHeight={useDynamicRowHeight ? this._getRowHeight : rowHeight}
rowGetter={rowGetter}
rowCount={rowCount}
scrollToIndex={scrollToIndex}
sort={this._sort}
sortBy={sortBy}
sortDirection={sortDirection}
width={width}>
{!hideIndexRow && (
<Column
label="Index"
cellDataGetter={({rowData}) => rowData.index}
dataKey="index"
disableSort={!this._isSortEnabled()}
width={60}
/>
)}
<Column
dataKey="name"
disableSort={!this._isSortEnabled()}
headerRenderer={this._headerRenderer}
width={90}
/>
<Column
width={210}
disableSort
label="The description label is really long so that it will be truncated"
dataKey="random"
className={styles.exampleColumn}
cellRenderer={({cellData}) => cellData}
flexGrow={1}
/>
</Table>
)}
</AutoSizer>
</div>
</ContentBox>
);
}
_getDatum(list, index) {
return list.get(index % list.size);
}
_getRowHeight({index}) {
const {list} = this.context;
return this._getDatum(list, index).size;
}
_headerRenderer({dataKey, sortBy, sortDirection}) {
return (
<div>
Full Name
{sortBy === dataKey && <SortIndicator sortDirection={sortDirection} />}
</div>
);
}
_isSortEnabled() {
const {list} = this.context;
const {rowCount} = this.state;
return rowCount <= list.size;
}
_noRowsRenderer() {
return <div className={styles.noRows}>No rows</div>;
}
_onRowCountChange(event) {
const rowCount = parseInt(event.target.value, 10) || 0;
this.setState({rowCount});
}
_onScrollToRowChange(event) {
const {rowCount} = this.state;
let scrollToIndex = Math.min(
rowCount - 1,
parseInt(event.target.value, 10),
);
if (isNaN(scrollToIndex)) {
scrollToIndex = undefined;
}
this.setState({scrollToIndex});
}
_rowClassName({index}) {
if (index < 0) {
return styles.headerRow;
} else {
return index % 2 === 0 ? styles.evenRow : styles.oddRow;
}
}
_sort({sortBy, sortDirection}) {
const sortedList = this._sortList({sortBy, sortDirection});
this.setState({sortBy, sortDirection, sortedList});
}
_sortList({sortBy, sortDirection}) {
const {list} = this.context;
return list
.sortBy(item => item[sortBy])
.update(
list => (sortDirection === SortDirection.DESC ? list.reverse() : list),
);
}
_updateUseDynamicRowHeight(value) {
this.setState({
useDynamicRowHeight: value,
});
}
}
Looking at some previous questions, it seems that the example is using some components that are not included inside dist package. Thats probably why you are getting undefined error.
Here is the most basic example of Tables in react virtulized:
import React from 'react';
import ReactDOM from 'react-dom';
import { Column, Table } from 'react-virtualized';
import 'react-virtualized/styles.css'; // only needs to be imported once
// Table data as an array of objects
const list = [
{ name: 'Brian Vaughn', description: 'Software engineer' }
// And so on...
];
// Render your table
ReactDOM.render(
<Table
width={300}
height={300}
headerHeight={20}
rowHeight={30}
rowCount={list.length}
rowGetter={({ index }) => list[index]}
>
<Column
label='Name'
dataKey='name'
width={100}
/>
<Column
width={200}
label='Description'
dataKey='description'
/>
</Table>,
document.getElementById('example')
);
When learning new library, its always best to start with the most simple example then expand on it. Here is the link to the full table docs.
The issue with the example is that in order for contextTypes to work, the parent component needs to define corresponding contextTypes and a getChildContext function.
In the parent component:
class App extends React.Component {
static childContextTypes = {
list: PropTypes.instanceOf(Immutable.List).isRequired
};
getChildContext() {
return {
list
};
}
render() {
return <TableExample />;
}
}
Mentioned in this issue; see lines 48-53 and 68-76 of the react-virtualized demo Application.js.

Resources