I am having an issue trying to get a scrolling table to work in React JS. I am also using skeleton. I only mention this, just in case there is some kind of conflict with skeleton and scrolling tables that I don't know about.
I currently have the following React JS component:
HistoryContainer.jsx
import React from 'react';
import HistoryItem from './historyItem';
export default class HistoryContainer extends React.Component {
render(){
var self=this;
return (
<div>
<h6><strong>{'Service History'}</strong></h6>
<table>
<tbody styles={'height: 100px; overflow: scroll;'}>
{
self.props.historyItems.map(function(historyItem)
{
return (
<HistoryItem historyItem={historyItem}/>
)
})
}
</tbody>
</table>
</div>
);
} }
HistoryItem.jsx:
import React from 'react';
export default class HistoryItem extends React.Component{
convertDate(data)
{
var d= new Date(data);
return (d.getMonth()+1)+'\\'+d.getDate()+"\\"+ d.getFullYear();
}
render(){
if(this.props.historyItem.WorkPerformedSummary==='')
{
return null;
}
return(
<div className='row'>
<tr>
<td><strong>{this.props.historyItem.WorkPerformedSummary}</strong></td>
{ this.props.historyItem.CompletedDate ? <td>
{this.convertDate(this.props.historyItem.CompletedDate)}
</td>: <td> {'n/a'} </td> }
</tr>
</div>
);
}
}
So, my issue is, I can't get the table inside of the HistoryContainer.jsx to have a scrollbar, even with the styling in the <tbody>. Any ideas?
Thanks
You need to convert tbody into a block level elements in order for them to be scrollable. Try adding display: block; to tbody and thead.
Got it working. I had to change my code to this
<tbody style={{'height': '300px', 'overflow':'scroll', 'display': 'block'}}>
and also
<thead style={{'display': 'block'}}>
Related
I'm building an application to save locations i.e countries cities regions etc. When clicking on my on click function the states of two div tags change changing the class name and making one invisible and one visible. advice?
import React, { useState }from "react";
import Area from "../ReadFolder/geographicMainComponents/areaMainComponent.jsx";
import City from "../ReadFolder/geographicMainComponents/cityMainComponent.jsx";
import Country from "../ReadFolder/geographicMainComponents/countryMainComponent.jsx";
import Neighborhood from "../ReadFolder/geographicMainComponents/neighborhoodMainComponent.jsx";
import Region from "../ReadFolder/geographicMainComponents/regionMainComponent.jsx";
import { default as AreaW} from "../WriteFolder/geographicMainComponents/areaMainComponent.jsx";
import { default as CityW} from "../WriteFolder/geographicMainComponents/cityMainComponent.jsx";
import { default as CountryW} from "../WriteFolder/geographicMainComponents/countryMainComponent.jsx";
import { default as NeighborhoodW} from "../WriteFolder/geographicMainComponents/neighborhoodMainComponent.jsx";
import { default as RegionW} from "../WriteFolder/geographicMainComponents/regionMainComponent.jsx";
export default function MenuWrapper({type,id,isEdit}){
let [edit,setEdit] = useState(isEdit);
let changer=()=>{console.log('you clicked me!');setEdit(!setEdit)}
if(type==='country'){
return(
<div key={"frommenulist"+id}>
<div className={edit ? 'd-block' :'d-none'}><CountryW id={id}/><button onClick={changer}>read</button></div>
<div className={edit ? 'd-none' : 'd-block'}><Country id={id} /><button onClick={changer}>edit</button></div>
</div>
);
}
}
It's difficult to work out what clicking those buttons is meant to do. It looks like you need only one div/button block, and clicking the edit button determines what happens (ie to make the country editable somehow).
At the moment it looks like you want to set the display to either block/none but you can't set an element's display to none and still expect to be able to click the button to reset the display because there will be no button to click on. Further: unless the type is "country" the component doesn't return anything so you need a condition in there to return something if type isn't "country" (or add a condition in the parent component to prevent the component rendering at all if that condition is met).
Here's a small example that uses local state to manage whether the div is a plain one or an editable one. Click the edit button, and then click in the div to be able to edit it. You can then click the read button to switch off contentEditable and keep the content.
const { useState } = React;
function MenuWrapper({ type, id }) {
const [ edit, setEdit ] = useState(false);
function handleClick() {
setEdit(!edit);
}
// Return a default div if type is not "country"
if (type !== 'country') return <div>Not country</div>
const divStyle = [
'country',
edit && 'edit'
].join(' ');
return (
<div>
<div>
<div
className={divStyle}
contentEditable={edit}
>Country Id: {id}
</div>
<button onClick={handleClick}>
{edit ? 'Read' : 'Edit'}
</button>
</div>
</div>
);
}
ReactDOM.render(
<MenuWrapper type="country" id="1" />,
document.getElementById('react')
);
.country { padding: 0.25em; }
.edit { border: 1px solid green; }
button { margin-top: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
This question already has answers here:
React 'cannot read property of undefined' when using map
(4 answers)
Closed 5 years ago.
I've just started looking basics of ReactJs. Following is my component to show list of buses. What I want exactly is I want to perform edit/delete operations over buses. But not able to pass busId of corresponding bus to my edit/delete methods.
Following is component code
import React, {Component} from "react";
import { withRouter } from 'react-router-dom'
import {Table,Badge, Label,FormGroup,Container, Row, Col, CardGroup, Card, CardBlock,CardHeader, Button, Input, InputGroup, InputGroupAddon} from "reactstrap";
import {appSettings} from '../../../../Utils/Util.js';
import Pagination from "react-js-pagination";
var axios = require('axios');
class BusList extends React.Component {
constructor(props) {
super(props);
this.state = {
busList:[]
};
this.loadBuses = this.loadBuses.bind(this);
}
componentWillMount() {
this.loadBuses();
}
loadBuses() {
var url = ‘my-api-complete-url-here’;
axios.get(url)
.then((result) => {
var key = 0;
var buses = result.data.map(function(bus,i){
return <tr key={key++}>
<td key={key++}>{bus.id}</td>
<td key={(key++)}>{bus.number}</td>
<td key={(key++)}>
<Button onClick={(e)=>this.editBus(e, bus.id)}>Edit</Button>
<Button onClick={(e)=>this.deleteBus(e, bus.id)}>Delete</Button>
</td>
</tr>
});
this.setState({busList: buses});
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<div className="animated fadeIn">
<Table hover responsive striped>
<thead>
<tr>
<th>Sr #</th>
<th>Bus Number</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{this.state.busList}
</tbody>
</Table>
</div>
);
}
editBus(id, e) {
console.log(‘Edit - Bus Id = ' +id);
}
deleteBus(id, e) {
console.log('Delete - Bus Id = ' +id);
}
}
export default BusList;
But when tapped on edit button, I receive this error(
Screenshot)
you're accessing it in wrong order, you're passing (e)=>this.editBus(e, bus.id) and in function you've defined editBus(id, e)
moreover you need to bind(this) at the end of map function
var buses = result.data.map(function(bus,i){
return <tr key={key++}>
<td key={key++}>{bus.id}</td>
<td key={(key++)}>{bus.number}</td>
<td key={(key++)}>
<Button onClick={(e)=>this.editBus(e, bus.id)}>Edit</Button>
<Button onClick={(e)=>this.deleteBus(e, bus.id)}>Delete</Button>
</td>
</tr>
});
Also, you don't need to define key variable. Instead, use second argument i of map function as it is the index of array element.
updated
you need to change your map code with
var buses = result.data.map(function(bus,i){
return <tr key={key++}>
<td key={key++}>{bus.id}</td>
<td key={(key++)}>{bus.number}</td>
<td key={(key++)}>
<Button onClick={(e)=>this.editBus(e, bus.id)}>Edit</Button>
<Button onClick={(e)=>this.deleteBus(e, bus.id)}>Delete</Button>
</td>
</tr>
}.bind(this));
The .bind(this) in the last line does the trick.
Basically I want to add an static HTML to a react component from external script.
So I'm saving the reference of this to window variable as follows:
let { PropTypes } = React;
export default class Body extends React.Component {
constructor(){
super();
let frmTrgt={};
frmTrgt.refff=this;
console.log("tthis: ",this);
window.bdyRefrence=frmTrgt;
}
static defaultProps = {
items: []
};
static propTypes = {
items: PropTypes.array.isRequired
};
render() {
return (
<div className={styles.body}>
<h1 className={styles.header}>React Seed</h1>
<p>This is an example seed app, powered by React, ES6 & webpack.</p>
<p>Here is some example data:</p>
<Menu items={this.props.items} />
<div>
<h1>Dynamic Content</h1>
<div id="myDynamicContent"></div>
</div>
</div>
);
}
}
and in my script tag in INDEX.html( Outside Script) I'm doing like following:
function addPHtml() {
try {
window.bdyRefrence.refff.refs.formTarget.insertAdjacentHTML("<p id='mhere'>paragraph 2</p>");
}catch (err){
console.log("err: ",err);
}
}
but when I'm calling addPHtml it is giving following error:
err: TypeError: Cannot read property 'insertAdjacentHTML' of undefined
at addPHtml ((index):19)
at <anonymous>:1:1
What your trying to do is not the correct way to insert the element in React, still for you requirement please refer below mentioned code
Your render function should be like
return(
<div>
<div ref="formTarget"></div>
<h1 >React Seed</h1>
<p>This is an example seed app, powered by React, ES6 & webpack.</p>
<p>Here is some example data:</p>
<div>
<h1>Dynamic Content</h1>
<div id="myDynamicContent"></div>
</div>
</div>
)
Please check Demo here Demo
In case using new React syntax (Createclass is deprecated now) use
window.refferedItem.refs.formTarget.getDOMNode().insertAdjacentHTML
I'm having an issue with editing a value in my React app. I'm aware of how controlled components work, and my problem isn't related to that.
I can paste text into it and see state for the input change, but when I try to change it myself nothing happens. The input resides inside of a TableHeader component.
import React from "react";
import classNames from "classnames";
class TableHeader extends React.Component {
constructor(props) {
super(props);
this.state = {
columnFilterText : "",
filterBoxOpen : false
}
this.toggleSortBox = this.toggleSortBox.bind(this);
this.handleColumnInputChange = this.handleColumnInputChange.bind(this);
}
toggleSortBox(event, value) {
if(event.target === event.currentTarget) {
this.setState({
filterBoxOpen: !this.state.filterBoxOpen
});
}
}
handleColumnInputChange(event) {
console.log(event)
this.setState({
columnFilterText: event.target.value
})
}
render() {
let tableHeaderClasses = classNames({
"sortable" : true,
"filter-box-open" : this.state.filterBoxOpen
});
let sortOptionClasses = classNames({
"sort-option" : true
});
return (
<th className={tableHeaderClasses} onClick={this.toggleSortBox}>
<div className="sort-box">
<div className="sort-option-container">
<div className={sortOptionClasses}>Sort - ascending</div>
</div>
<div className="sort-option-container">
<div className={sortOptionClasses}>Sort - descending</div>
</div>
<hr className="divider" />
<input onChange={this.handleColumnInputChange} type="text" value={this.state.columnFilterText} />
<div className="row">
<button className="six columns">Apply</button>
<button className="six columns">Clear</button>
</div>
</div>
{this.props.label}
</th>
);
}
}
export default TableHeader;
I've checked if it's a css issue, by disabling styles, but the input field is still disabled, so no luck there. Any ideas what might be causing the issue?
I'm an idiot. The reason for this was that I had a keyDown event on the parent component for keyboard navigation, with event.preventDefault(); which of course affected the child component.
Thanks to everyone for contributing and for trying to help!
I have started to get my hand-on reactjs. I have three components which are placed in separate files. mainPage.js list.js and tableDisplay.jsare the three different files. I have got few doubt after working with reactjs.
The output from mainPage.js is passed as inputs to the list.js, so here
mainPage.js is parent and list.js is the child(if wrong please correct
me).Likewise, list.js output is passed as input to the tableDisplay.js,my doubt here is, does list.js remain as child component or act as parent component for the list.js.
The output fetched in the list.js is a table from the DB. So Im trying to
display the same table in the tableDisplay.js page, for which Im storing the fetched data to be an object. But Im getting an error Objects are not valid as a React child (found: object with keys {Name, Emp.no, Designation, WorkOff}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of tableDispay. So what does this error mean and how to overcome this error ad display the table in the tableDisplay.js
list.js :
class list extends React.Component {
constructor(props) {
super(props);
this.state = {
content: false,
query : '' ,
};
this.clickEvent= this.clickEvent.bind(this);
}
onChange(e) {
this.setState({ query : e.target.value });
}
clickEvent(event) {
event.preventDefault();
this.setState({
content: true,
});
connectDataBase.query(this.state.query, (err, result) => {
var dataFetched = result;
this.setState({
htmlTable: dataFetched,
});
})
}
render() {
return (
<div>
<div id="listClass">
<label> SQL </label>
<br />
<textarea rows="4" cols="50" onChange={this.onChange.bind(this)} value={this.state.query}> Query </textarea>
</div>
<button onClick={this.clickEvent.bind(this)} > Run </button>
<div id="third" >
{this.state.content && <TableDisplay tableData={this.state.htmlTable}/>}
</div>
</div>
)
}
}
export default list;
tableDisplay.js:
class tableDisplay extends React.Component{
constructor(props) {
super(props);
this.state = {
};
}
render(){
return(
<div id="tableClass" >
<label> Result </label>
<br/>
{this.props.tableData.map((x,y)=>
<table key={y}>
{x}
</table>
)}
{this.props.tableData};
</div>
)
}
}
export default tableDisplay;
I think error is in this line:
{this.props.tableData};
tableData is an array (as you are using map on that), and we can't render any array/object directly inside JSX, remove that line it will work.
Note: You can convert the array to string by using join then you can print the data directly.
Use this:
{this.props.tableData.join(' ')};
I think there is a issue with table rendering also, inside table you are directly putting the {x}, but you need to use some td/tr to render data.
You need to define the htmlTable and content in state variable, initial value of content should be false and once you get the data update the content value to true.
Content of tableData is:
[{Name : 'Sam', Emp.No:'12809', Designation:'Engg.', WorkOff :'UK'}]
Use this to render table:
<table>
{tableData.map((obj,y) => {
return <tr key={obj['Emp.No']}>
{Object.keys(obj).map((x,y) => <td key={y}> {obj[x]} </td>)
</tr>
})}
</table>