How to handle 'Enter' on Input in React - node.js

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}

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

Filtering locally rendered JSON table in React

I have a page in my React App that renders some locally stored JSON Data into a table. I've been trying for a long time to implement a search bar that will filter through the PostCode column in the table and return the row. So far I've been able to make a search bar that does what I want it to but I haven't been able to integrate it into the page with the table.
My apologies if this is an easy question or I'm way off the mark. I'm a coding novice but have to use React for a project and struggle to get to grips with it.
The code for my table looks like this:
import SearchBar from './SearchBar'
import React,{useState,useEffect} from 'react';
import './App.css';
import { Data } from './NewData.js'
export const JsonReader = () => {
return (
<>
<ArchiveHeader />
<div className="data-container">Welcome to RF</div>
{Data.map((data, key) => {
return (
<div key={key}>
<JsonTable
key = {key}
Username = {data.Username}
Address = {data.Address}
PostCode = {data.PostCode}
Details ={data.Details}
Date ={data.Date}
Score ={data.Score}
/>
</div>
);
})}
</>
);
};
const ArchiveHeader = () => {
return (
<header className="ArchiveHeader">
<h2>Rent Flag</h2>
</header>
);
};
const JsonTable= ({ Username, Address, PostCode, Details, Date, Score }) => {
if (!Username) return <div />;
return (
<table data={Data}>
<tbody>
<tr>
<td>
<h5>{Username}</h5>
</td>
<td>
<h5>{Address}</h5>
</td>
<td>
<h4>{PostCode}</h4>
</td>
<td>
<p>{Details}</p>
</td>
<td>
<p>{Date}</p>
</td>
<td>
<p>{Score}</p>
</td>
</tr>
</tbody>
</table>
);
};
export default JsonReader;
and the code for my searchbar looks like this:
import Papa from "papaparse";
import React, { useState, useEffect } from 'react';
import { Data } from './NewData.js'
import JsonReader from './JsonReader'
export default function SearchBar () {
const [searchTerm,setSearchTerm] = useState('')
return (
<div className="SearchBar">
<input type="text" placeholder="search..." onChange={e=>setSearchTerm(e.target.value)} />
{Data.filter((val)=>{
if(searchTerm == ""){
return val
}
else if(val.PostCode.toLowerCase().includes(searchTerm.toLowerCase())){
return val;
}
}).map((val,key)=>{
return <div>{val.PostCode} </div>
})}
</div>
);
}
You can use useMemo hook for this functionality.
const searchResults = useMemo(() => {
if (!searchTerm) {
return items;
}
return Data?.filter((item) =>
item?.toLowerCase()?.includes(searchTerm?.toLowerCase().trim())
);
}, [Data, searchTerm]);
You can use searchResults variable and render that in your table.
In the same JsonReader function you should:
Create the useState constants [searchTerm, setSearchTerm].
Set a new FData array with filtered data and that is the one you should do the mapping to.
Place the input field on the same page.
And, instead of using the Data.map you will use the FData.map.
This is how your JsonReader function should look like (and the SearchBar function could be discarded):
export const JsonReader = () => {
const [searchTerm, setSearchTerm] = useState("");
const FData = Data.filter((val) => {
if (searchTerm == "") {
return val;
} else if (val.PostCode.toLowerCase().includes(searchTerm.toLowerCase())) {
return val;
}
});
return (
<>
<ArchiveHeader />
<div className="data-container">Welcome to RF</div>
<input type="text" placeholder="search..." onChange={(e) => setSearchTerm(e.target.value)} />
{FData.map((data, key) => {
return (
<div key={key}>
<JsonTable
key = {key}
Username = {data.Username}
Address = {data.Address}
PostCode = {data.PostCode}
Details ={data.Details}
Date ={data.Date}
Score ={data.Score}
/>
</div>
);
})}
</>
);
};

Problem with Select mui and Object value dissapears

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

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.

What is the right way to call React component?

I encountered problem with react component. Basically, i use NPM integrated with Rails and called React component in my rails app.
I try to call react-file-base64 module in my code like below :
const FileBase64 = require('react-file-base64');
var MembersNew = React.createClass(
{
render()
{
return(
<div>
<h5>ACCOUNT DETAILS</h5>
<hr/>
<p>Fill in your member account details below</p>
<b>Membership ID : </b>
<div className="row">
<div className="medium-6 columns">
<FileBase64/> <------ Called component
<label>Username*
<input ref="name" type="text"/>
</label>
<label>First Name*
<input ref="name" type="text"/>
</label>
<label>Last Name*
<input ref="name" type="text"/>
</label>
<label>Email Address*
<input ref="name" type="text"/>
</label>
</div>
</div>
)
I got following error :
Below is react-file-base64.js :
import React from 'react';
import ReactDOM from 'react-dom';
class FileBase64 extends React.Component {
constructor() {
super()
this.state = {
files: []
}
this.props = {
multiple: false
}
}
handleChange(e){
// get the files
let files = e.target.files;
// Process each file
var allFiles = []
for (var i = 0; i < files.length; i++) {
let file = files[i]
// Make new FileReader
let reader = new FileReader()
// Convert the file to base64 text
reader.readAsDataURL(file)
// on reader load somthing...
reader.onload = () => {
// Make a fileInfo Object
let fileInfo = {
name: file.name,
type: file.type,
size: Math.round(file.size / 1000)+' kB',
base64: reader.result,
file: file
}
// Push it to the state
allFiles.push(fileInfo)
// If all files have been proceed
if(allFiles.length == files.length){
// Apply Callback function
if(this.props.multiple) this.props.onDone(allFiles)
else this.props.onDone(allFiles[0])
}
} // reader.onload
} // for
}
render(){
return (
<div>
<input
type="file"
onChange={ this.handleChange.bind(this) }
multiple={ this.props.multiple } />
</div>
)
}
}
export default FileBase64;
I think what i did was wrong. If there's anyone could guide me on how can i achieve this. I really appreciate that.

Resources