问题
Hi i have problem with my table in bootstrap. I am getting data from server about timetable. This data i am saving in state. Next i am creating table. (Two ways of creating mobile and pc, just changing position of days and hours). Every column contains component SubjectColumn (there will be more data in one column like class and subject name). So when I click on this subject column i need to open modal with clicked subject data and after choosing of list of subjects in modal, I have to change subject for new one. I get subject data in my modal but i don't know how to change them for new one. Any idea please?
export class Schedule extends Component {
static contextType = LoggedInuserContext;
constructor(props) {
super(props);
this.state = {
editMode: false,
openModal: false,
schedule: null,
modalShow: false,
mySubjects: null,
selectedSubject:null
};
this.resize = () => this.forceUpdate();
}
changeModalState() {
this.setState({modalShow: !this.state.modalShow})
}
selectSubject(subject){
this.setState({selectedSubject:subject},this.changeModalState);
}
componentDidMount() {
window.addEventListener('resize', this.resize)
this.getTimeTable().then(r =>
this.setState({isScheduleLoaded: true})
);
this.getMySubjects();
}
componentWillUnmount() {
window.removeEventListener('resize', this.resize)
}
async getTimeTable() {
if (this.context == null) return;
const response = await fetch('UserController/GetTimeTable/' + this.context.user.id + '/' + this.context.company + '/' + this.context.role.id);
this.setState({schedule: await response.json()});
}
async getMySubjects() {
if (this.context == null) return;
const response = await fetch('SubjectTreeController/GetUserSubjectsList/' + this.context.user.id + '/' + this.context.company + '/' + this.context.role.id);
this.setState({mySubjects: await response.json()});
}
createContent() {
if (!this.state.isScheduleLoaded === true) return;
let header_data = [];
let body_data = [];
//For mobile else pc
if (window.innerWidth < 768) {
//Header of table
this.state.schedule.days.forEach(day => {
header_data.push(day.name.substring(0, 2))
});
//Body of table
for (let i = 0; i < this.state.schedule.days[0].slots.length; i++) {
let row = {
firstColumn: i,
other: []
};
this.state.schedule.days.forEach((day, key) => {
row.other.push(day.slots[i]);
});
body_data.push(row);
}
} else {
//Header of table
this.state.schedule.days[0].slots.forEach(slot => {
header_data.push(slot.order)
});
//Body of table
this.state.schedule.days.forEach(day => {
let row = {
firstColumn: [],
other: []
};
row.firstColumn.push(day.name);
day.slots.map(slot => row.other.push(slot));
body_data.push(row);
});
}
let head = this.createTableHead(header_data);
let body = this.createRows(body_data);
return (
<>
<thead>
{head}
</thead>
<tbody>
{body}
</tbody>
</>
);
}
createTableHead(data) {
return (
<tr>
<td></td>
{data.map((d, k) => {
return (<th key={k} className={"text-center"}> {d} </th>)
})}
</tr>
);
}
createRows(data) {
const items = [];
for (let i = 0; i < data.length; i++) {
const row = [];
for (let j = 0; j < data[i].other.length; j++) {
if (data[i].other[j].subject !== null) {
row.push(<td key={j} className={"text-center "}><SubjectColumn editMode={this.state.editMode}
subject={data[i].other[j].subject}
selectSubject={this.selectSubject.bind(this)}>
</SubjectColumn>
</td>);
} else {
row.push(<td key={j} className={"text-center "}><SubjectColumn editMode={this.state.editMode}
subject={null}
selectSubject={this.selectSubject.bind(this)}
>
</SubjectColumn>
</td>);
}
}
items.push(
<tr key={i}>
<td>{data[i].firstColumn}</td>
{row}
</tr>
);
}
return items;
}
loading() {
if (this.state.schedule === null)
return (
<div className={"d-flex flex-column justify-content-center text-center"}>
<div>
<Spinner animation="grow" variant="success"/>
<Spinner animation="grow" variant="danger"/>
<Spinner animation="grow" variant="warning"/>
</div>
<span>Načítam rozvrh</span>
</div>
);
}
showActionButtons() {
const items = [];
if (this.state.editMode) {
items.push(<Button key={"save"} className={"px-4 mx-1"} variant={"success"}
onClick={this.startEditing.bind(this)}>Uložiť</Button>)
}
items.push(
<Dropdown key={"settings"} alignRight>
<Dropdown.Toggle variant="dark" id="dropdown-basic">
<FontAwesomeIcon icon={faCog} size={"lg"}/>
</Dropdown.Toggle>
<Dropdown.Menu>
<Dropdown.Item onClick={this.startEditing.bind(this)}>Edituj rozvrh</Dropdown.Item>
</Dropdown.Menu>
</Dropdown>
);
return items;
}
startEditing() {
this.setState({editMode: !this.state.editMode});
}
openScheduleSetting() {
console.log("open");
// this.setState({openModal: true});
}
closeScheduleSetting() {
console.log("close");
// this.setState({openModal: false});
}
render() {
return (
<div className={"w-100"} id="schedule">
<div className={"d-flex justify-content-center my-2"}>
<h3 className={"my-1 text-left flex-grow-1 pl-2"}>Rozvrh hodín</h3>
{this.showActionButtons()}
</div>
<Table striped bordered hover>
{this.createContent()}
</Table>
{this.loading()}
<ScheduleSelectModal subject={this.state.selectedSubject} subjectslist={this.state.mySubjects} show={this.state.modalShow} onHide={this.changeModalState.bind(this)}>
</ScheduleSelectModal>
</div>
);
}
}
SubjectColumn
export class SubjectColumn extends Component {
showModalInParrent(){
console.log(this.props);
this.props.selectSubject(this.props.subject);
}
createCell() {
let items = null;
if (this.props.editMode) {
if(this.props.subject === null){
return ( <Button className={"w-100 h-100"} onClick={this.showModalInParrent.bind(this)}> </Button>)
}
items = (
<Fragment>
<Button className={"w-100 h-100"} onClick={this.showModalInParrent.bind(this)}> {this.props.subject.acronym } </Button>
</Fragment>
);
return items;
} else {
if(this.props.subject === null){
return;
}
return (this.props.subject.acronym );
}
}
render() {
return (
<div className="w-100 h-100">
{this.createCell()}
</div>
);
}
}
Modal:
import React, {Component, Fragment} from "react";
import Modal from "react-bootstrap/Modal";
import ButtonGroup from "react-bootstrap/ButtonGroup";
import Button from "react-bootstrap/Button";
export class ScheduleSelectModal extends Component {
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("modal props:");
console.log(this.props.subject);
}
createList() {
let items = [];
if (this.props.subjectslist !== null)
this.props.subjectslist.map(subject =>
items.push(<Button key={subject.id} block className={"my-1"}>{subject.name} </Button>)
);
return items;
}
renderHeader(){
if(this.props.subject === null){
return(
<p>
Vyberťe subjekt ktorý chcete nahradiť
</p>
)
}
else{
return( <p>
{this.props.subject.name }
</p>);
}
}
render() {
return (
<Modal
{...this.props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
{this.renderHeader()}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<ButtonGroup vertical className={"w-100"}>
{this.createList()}
</ButtonGroup>
</Modal.Body>
</Modal>
);
}
}
This loos like my shedule object
Object
id: 1
dateUpdated: "2020-03-24T17:36:48.66"
days: Array(5)
0: {slots: Array(8), id: 1, order: 1, name: "Pondelok", acronym: "PO", …}
1:
slots: Array(8)
0: {order: 0, subject: null, studentGroup: null}
1: {order: 1, subject: null, studentGroup: null}
2: {order: 2, subject: {…}, studentGroup: null}
3:
order: 3
subject:
note: ""
id: 5
name: "Biológia"
acronym: "B"
__proto__: Object
studentGroup: null
__proto__: Object
4: {order: 4, subject: {…}, studentGroup: null}
5: {order: 5, subject: null, studentGroup: null}
6: {order: 6, subject: null, studentGroup: null}
7: {order: 7, subject: null, studentGroup: null}
length: 8
__proto__: Array(0)
id: 2
order: 2
name: "Utorok"
acronym: "UT"
isWeekend: 0
__proto__: Object
2: {slots: Array(8), id: 3, order: 3, name: "Streda", acronym: "ST", …}
3: {slots: Array(8), id: 4, order: 4, name: "Štvrtok", acronym: "ŠT", …}
4: {slots: Array(8), id: 5, order: 5, name: "Piatok", acronym: "PIA", …}
length: 5
__proto__: Array(0)
__proto__: Object
回答1:
If I've undeerstood your q, this might work for you:
- In the modal where you show
selectedSubject
, replace each value (text) you want to edit with input element. - changing value in input should update
state.selectedSubject
inSchedule
component or you might have state in modal to capture editedselectedSubject
, but why duplicating data if you don't have to. I would go with updating parent component state. Schedule
component should have method which will make put (or patch) request with edited data.- Pass this method to the modal.
- Add "Save" button to the modal. When you finish editing, clicking on "Save" button should fire passed method.
- Optional: you can have success message in your modal (success or error)
来源:https://stackoverflow.com/questions/60979021/how-to-update-data-for-table-column-in-react