我有2个组件1 /父级---->将删除功能传递给子Component,但它导致未定义
TypeError: Cannot read property 'onHandleDelete' of undefined
我尝试了所有可反应文档提供的功能,但对我没有任何帮助 父组件
import React from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
// import isEmpty from 'lodash/isEmpty';
import { connect } from 'react-redux';
import isObject from 'lodash/isObject';
import classnames from 'classnames';
import moment from 'moment-hijri';
import uuid from 'uuid';
// Material-UI
import { withStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';
// components
import Actions from './Actions';
import Supervisor from './Supervisor';
// Forms
import Entity from '~/Components/Entity';
import { BaseFormComponent, Form, FormBreak, FormDivider, FormContainer, FormItem } from '~/Components/FormComponent';
import { LabelAndValue } from '~/Components/FormComponent/Controls';
import {
isRequired,
noEnglish,
isObjectRequired,
} from '~/Services/Validators';
// Redux
import OfficesActions from '~/Redux/Actions/Offices';
import { VisitStatus } from '~/Services/StaticLookups';
import Strings from '~/Services/Strings';
import Notifications from '~/Services/Notifications';
import Message from '~/Components/Message';
import Navigate from '~/Services/Navigate';
import styles from './styles';
@withStyles(styles)
class AssignmentsEditorScreen extends BaseFormComponent {
constructor(props) {
super(props);
this.initState({
supervisors: [],
insititution: [],
inistitutionsLookup: [],
selectedSupervisors: [],
previousSupervisorsFromId: [],
plannedVisitInfoFromId: {},
institutionDetails: {},
account: {},
error: false,
form: {
id: {
type: this.types.string,
value: 0,
},
institutionId: {
type: this.types.number,
validators: [ isRequired() ],
},
visitTypeId: {
type: this.types.number,
validators: [ isRequired() ],
},
startDate: {
type: this.types.object,
validators: [ isObjectRequired() ]
},
endDate: {
type: this.types.object,
validators: [ isObjectRequired() ]
},
office: {
type: this.types.string,
UIOnly: true
},
plannedVisitSupervisors: {
type: this.types.string,
UIOnly: true
},
visitStatus: {
type: this.types.string,
UIOnly: true
},
reason: {
type: this.types.string,
validators: [ noEnglish() ],
},
},
});
}
componentDidMount() {
super.componentDidMount();
const id = get(this, 'props.match.params.id', null);
const { offices, account } = this.props;
this.searchableEntity.get();
if (id) {
this.addFormFields({
referenceNumber: {
type: this.types.string,
UIOnly: true
},
});
this.entity.get({ id });
} else {
this.removeFormFields([ 'referenceNumber' ]);
}
if (!offices.isSet) {
this.props.getOffices();
}
this.setState({ account });
}
componentDidUpdate(prevProps) {
if(this.state.account !== this.props.account) {
const employeeOfficeId = this.props.account.myRoles.find(item => item.roleName === 'PTSupervisionEmployees').officeId;
// // To Switch to employee Office Once he Opens The Editor
this.handleOfficesChange(employeeOfficeId);
this.setFieldValue('office', employeeOfficeId);
this.setState({ account: this.props.account });
}
}
onSubmit() {
const id = get(this, 'props.match.params.id', null);
const { selectedSupervisors, previousSupervisorsFromId } = this.state;
let plannedVisitors = [];
if(selectedSupervisors.length > 0) {
selectedSupervisors.map(item => {
plannedVisitors.push({ supervisorName: item.name });
});
} else {
plannedVisitors = [];
}
// To Append The Previous Supervisors with the newest supervisors
if(previousSupervisorsFromId.length > 0) {
previousSupervisorsFromId.map(item => {
plannedVisitors.push({ supervisorName: item.supervisorName });
});
}
if (this.isFormValid) {
this.entity.post({
...this.formValues,
plannedVisitSupervisors: [ ...plannedVisitors ],
// to set id = 0 --> in create Mode || id Value in update Mode
id: id ? id : 0
});
} else {
console.log('this', this.formValues,);
this.showFormErrors();
}
}
onEntityPosted() {
const id = get(this, 'props.match.params.id', null);
if(id) {
Notifications.notify('success', Strings.assignmentUpdatedSuccessfuly);
} else {
Notifications.notify('success', Strings.assignmentSavedSuccessfully);
}
Navigate.go('/plannedvisits');
}
onEntityPostedError(data) {
if(data === 'Failed to create visit!, another visit is on for the institution!') {
Notifications.notify('error', Strings.duplicatPlannedVisits);
this.setState({ error: true });
}
}
onEntityReceived(data) {
const previousSupervisorsFromId = [ ...data.plannedVisitSupervisors ];
const plannedVisitInfoFromId = { ...data };
if(isObject(data)) {
this.updateFormValues(data, () => {
if(data.hasOwnProperty('visitReasonId')) {
this.addFormFields({
visitReasonId: {
type: this.types.number,
validators: [ isRequired() ],
value: data.visitReasonId,
}
});
}
});
}
this.setState({
previousSupervisorsFromId,
plannedVisitInfoFromId
});
}
onSearchableEntityReceived(data) {
if(data && data.licensingInstitutionsModel) {
const insititution = [ ...data.licensingInstitutionsModel ];
if (data.licensingInstitutionsModel && data.licensingInstitutionsModel.length > 0) {
{
data.licensingInstitutionsModel.map(item => {
this.setState(prevState => ({
inistitutionsLookup: prevState.inistitutionsLookup.concat({
id: item.institutionId,
nameAr: item.fullName
}),
insititution
}));
});
}
}
}
}
onSupervisorsByOfficeEntityReceived(data) {
this.setState({ supervisors: data.result });
}
handleOfficesChange(officeId) {
this.supervisorsByOfficeEntity.get({ officeId });
}
onHandleDelete(member) {
console.log('member', member);
}
x(m) {
console.log('member');
}
handleReasonField(id) {
if(id === 1) {
this.addFormFields({
visitReasonId: {
type: this.types.string,
validators: [ isRequired() ]
},
});
} else {
this.removeFormFields([ 'visitReasonId' ]);
}
}
getInstitutionValues(institutionId) {
const { insititution } = this.state;
if(insititution && insititution.length > 0) {
const institutionDetails = insititution.filter(item => item.institutionId === institutionId);
this.setState({ institutionDetails });
}
}
handleAddMember(value) {
const member = this.state.supervisors.find(item => item.name === value);
if(member) {
// in order not to allow add multiple supervisors withe the same name
const isInPreviousSupervisors = this.state.previousSupervisorsFromId.find(item => item.supervisorName === member.name);
if(!isInPreviousSupervisors) {
const selectedSupervisors = [ ...this.state.selectedSupervisors ];
selectedSupervisors.push(member);
this.setState({ selectedSupervisors });
} else {
Notifications.notify('error', `${member.displayName} ${Strings.userAlreadyInTheList} ${member.name}`);
}
}
}
get offices() {
const { offices } = this.props;
if(offices.list.length >= 1) {
const lookup = {};
offices.list.forEach(item => {
lookup[item.id] = item.name;
});
return lookup;
}
return {};
}
get plannedVisitsSupervisors() {
const lookup = {};
this.state.supervisors.forEach(item => {
const isSelectedBefore = this.state.selectedSupervisors.find(sItem => sItem.name === item.name);
if(!isSelectedBefore) {
lookup[item.name] = item.displayName;
}
});
return lookup;
}
get getSupervisors() {
const { selectedSupervisors, previousSupervisorsFromId } = this.state;
return selectedSupervisors.concat(previousSupervisorsFromId);
}
render() {
// const { form, inistitutions, supervisorsByOffice, previousSupervisorsFromId } = this.state;
const { form, error, inistitutionsLookup, plannedVisitInfoFromId } = this.state;
const { classes } = this.props;
const id = get(this, 'props.match.params.id', null);
const inistitutionsCheck = inistitutionsLookup && inistitutionsLookup.length === 0;
// const supervisorsCheck = supervisorsByOffice && supervisorsByOffice.length === 0;
const disabled = plannedVisitInfoFromId && plannedVisitInfoFromId.plannedVisitActions && !plannedVisitInfoFromId.plannedVisitActions.allowEdit;
const {
TextField,
LookupSelectField,
StaticLookupSelectField,
SelectAutocompleteField,
Date2Field,
} = this;
return (
<React.Fragment>
<Entity
storeId={'Supervision-PlannedVisit-Editor'}
entityRef={ref => { this.entity = ref; }}
onEntityReceived={data => this.onEntityReceived(data)}
onEntityPosted={data => this.onEntityPosted(data)}
onEntityPostedError={data => this.onEntityPostedError(data)}
render={store => (
<Form loading={store.loading}>
<Grid container spacing={24}>
<If condition={error}>
<Grid item xs={12}>
<Message variant={'error'} text={Strings.duplicatPlannedVisits} />
</Grid>
</If>
<Grid item xs={9}>
<Paper elevation={1} className={classes.box1}>
<fieldset className={classes.fieldSet}>
<legend>{Strings.assignmentDetails}</legend>
<FormContainer>
<FormItem lg={6}>
<div className={classnames(classes.placeholder, id || inistitutionsCheck ? classes.disabledField : {})}>
<SelectAutocompleteField
name={'institutionId'}
label={Strings.assignmentInstitutionName}
emptyString={Strings.searchByNameAndLicense}
disabled={id || inistitutionsCheck}
data={inistitutionsLookup}
onChange={field => this.getInstitutionValues(field.value)}
// onSearch={e => console.log('e', e)}
/>
</div>
</FormItem>
<FormItem lg={form.visitTypeId.value === 1 ? 3 : 6}>
<LookupSelectField
name={'visitTypeId'}
label={Strings.assignmentvisitType}
lookup={'VisitType'}
onChange={field => this.handleReasonField(field.value)}
disabled={disabled}
/>
</FormItem>
<If condition={form.visitTypeId.value === 1 && form.visitReasonId}>
<FormItem lg={3}>
<LookupSelectField
name={'visitReasonId'}
label={Strings.assignmentvisitReason}
lookup={'VisitReason'}
disabled={disabled}
/>
</FormItem>
</If>
<FormItem lg={6}>
<Choose>
<When condition={disabled}>
<LabelAndValue
label={Strings.assignmentvisitStartDate}
value={plannedVisitInfoFromId.startDate.hijriDate}
/>
</When>
<Otherwise>
<Date2Field
name={'startDate'}
label={Strings.assignmentvisitStartDate}
minDate={[
moment().iYear(),
moment().iMonth() + 1,
moment().iDate()
]}
/>
</Otherwise>
</Choose>
</FormItem>
<FormItem lg={6}>
<Choose>
<When condition={disabled}>
<LabelAndValue
label={Strings.assignmentvisitEndDate}
value={plannedVisitInfoFromId.endDate.hijriDate}
/>
</When>
<Otherwise>
<Date2Field
name={'endDate'}
label={Strings.assignmentvisitEndDate}
minDate={[
moment().iYear(),
moment().iMonth() + 1,
moment().iDate()
]}
/>
</Otherwise>
</Choose>
</FormItem>
</FormContainer>
</fieldset>
</Paper>
<Paper elevation={1} className={classes.box}>
<fieldset className={classes.fieldSet}>
<legend>
<Choose>
<When condition={disabled}>
{Strings.assignedSupervisors}
</When>
<Otherwise>
{Strings.addSupervisors}
</Otherwise>
</Choose>
</legend>
<FormContainer className={classes.supervisorsContainer}>
<If condition={!disabled}>
<FormItem>
<div className={ classes.lookup }>
<StaticLookupSelectField
name= {'office'}
label={Strings.office}
lookup= {this.offices}
onChange={field => this.handleOfficesChange(field.value)}
/>
</div>
</FormItem>
<FormItem>
<StaticLookupSelectField
name={'plannedVisitSupervisors'}
label={Strings.supervisorListName}
lookup={this.plannedVisitsSupervisors}
onChange={field => this.handleAddMember(field.value)}
/>
</FormItem>
</If>
<If condition={this.getSupervisors.length > 0}>
<If condition={!disabled}>
<FormBreak />
<FormDivider />
<Typography variant='subtitle1' className={classes.supervisorsHeader}>
{Strings.assignedSupervisors}
</Typography>
</If>
<FormContainer className={classes.supervisorsContainer}>
<For each='member' of={this.getSupervisors} index='i'>
<FormItem lg={4} key={`${i}_${uuid()}`}>
<Supervisor
data={member}
onHandleDelete={data => this.onHandleDelete(data)}
disabled={disabled}
/>
</FormItem>
</For>
</FormContainer>
</If>
</FormContainer>
</fieldset>
</Paper>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth>
<TextField
multiline
name={'reason'}
label={Strings.assignmentvisitreason}
disabled={disabled}
/>
</FormItem>
</Paper>
</Grid>
<Grid item xs={3}>
{/* =========== Sidebar ============= */}
<If condition={form && form.visitStatus}>
<Paper elevation={1} className={classes.box}>
{/* lookup is Needed */}
<FormItem fullWidth>
<StaticLookupSelectField
name={'visitStatus'}
label={Strings.assignmentvisitStatus}
lookup={VisitStatus}
disabled
/>
</FormItem>
</Paper>
</If>
<If condition={form && form.referenceNumber}>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth>
<TextField
name={'referenceNumber'}
label={Strings.violationReferenceNumber}
disabled
/>
</FormItem>
</Paper>
</If>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth style={{ marginBottom: 10 }}>
<Actions disabled={disabled} onSubmit={() => this.onSubmit()} />
</FormItem>
</Paper>
</Grid>
</Grid>
</Form>
)}
/>
{/* To get all institutions */}
<Entity
storeId={'Supervision-Assignment-Searchable-Institution'}
entityRef={ref => { this.searchableEntity = ref;}}
onEntityReceived={data => this.onSearchableEntityReceived(data)}
/>
{/* To get supervisors by office */}
<Entity
storeId={'Supervision-Assignment-Supervisors-By-Office'}
entityRef={ref => { this.supervisorsByOfficeEntity = ref;}}
onEntityReceived={data => this.onSupervisorsByOfficeEntityReceived(data)}
/>
</React.Fragment>
);
}
}
AssignmentsEditorScreen.propTypes = {
classes: PropTypes.object,
offices: PropTypes.object,
account: PropTypes.object,
getOffices: PropTypes.func
};
const mapStateToProps = store => ({
offices: store.offices,
account: store.account.data || {}
});
const mapDispatchToProps = dispatch => ({
getOffices: () => dispatch(OfficesActions.get()),
});
AssignmentsEditorScreen.propTypes = {
classes: PropTypes.object,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(AssignmentsEditorScreen);
子组件
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Paper from '@material-ui/core/Paper';
import Icon from '@material-ui/core/Icon';
import IconButton from '@material-ui/core/IconButton';
import DeleteIcon from '@material-ui/icons/Delete';
import Tooltip from '@material-ui/core/Tooltip';
import strings from '~/Services/Strings';
import { supervisor } from './styles';
@withStyles(supervisor)
class Supervisor extends Component {
render() {
const { classes, data, disabled } = this.props;
console.log('da', data);
return (
<Paper className={classes.memberItem}>
<If condition={!disabled}>
<Tooltip title={strings.delete}>
<IconButton className={classes.delete} onClick={() => this.props.onHandleDelete(data)}>
<DeleteIcon />
</IconButton>
</Tooltip>
</If>
<div className={classes.memberIconWrapper}>
<Icon className={classes.memberIcon}>person</Icon>
</div>
<div className={classes.memberDetails}>
<div className={classes.subInfo}>
<Typography gutterBottom className={classes.memberJobTitle} variant='subtitle1'>
{strings.supervisorNameSub}
</Typography>
<Typography className={classes.memberName} variant='subtitle2'>
<Choose>
<When condition={data.displayName}>
{data.displayName}
</When>
<Otherwise>
<Choose>
<When condition={data.name}>
{data.name}
</When>
<Otherwise>
<Choose>
<When condition={data.supervisorName}>
{data.supervisorName}
</When>
<Otherwise>
{strings.emptyString}
</Otherwise>
</Choose>
</Otherwise>
</Choose>
</Otherwise>
</Choose>
</Typography>
</div>
<div className={classes.subInfo}>
<Typography gutterBottom className={classes.memberJobTitle} variant='subtitle1'>
{strings.assignedVisitCountSub}
</Typography>
<Typography className={classes.memberName} variant='subtitle2'>
<Choose>
<When condition={typeof(data.assignedVisitCount) === 'number'}>
{data.assignedVisitCount}
</When>
<Otherwise>
{strings.emptyString}
</Otherwise>
</Choose>
</Typography>
</div>
<div className={classes.subInfo}>
<Typography gutterBottom className={classes.memberJobTitle} variant='subtitle1'>
{strings.requiredVisitsCountPerMonthSub}
</Typography>
<Typography className={classes.memberName} variant='subtitle2'>
<Choose>
<When condition={typeof(data.requiredVisitsCountPerMonth) === 'number'}>
{data.requiredVisitsCountPerMonth}
</When>
<Otherwise>
{strings.emptyString}
</Otherwise>
</Choose>
</Typography>
</div>
</div>
</Paper>
);
}
}
Supervisor.propTypes = {
classes: PropTypes.object,
data: PropTypes.object,
disabled: PropTypes.bool,
key: PropTypes.string,
onHandleDelete: PropTypes.func,
};
export default Supervisor;
这是我的父组件
<For each='member' of={this.getSupervisors} index='i'>
<FormItem lg={4} key={`${i}_${uuid()}`}>
<Supervisor
data={member}
onHandleDelete={data => this.onHandleDelete(data)}
disabled={disabled}
/>
</FormItem>
</For>
这是onHandleDelete函数
onHandleDelete(data) {
console.log('member');
}
这是我的子组件(主管)
<If condition={!disabled}>
<Tooltip title={strings.delete}>
<IconButton className={classes.delete} onClick={() => this.props.onHandleDelete(data)}>
<DeleteIcon />
</IconButton>
</Tooltip>
</If>
这是来自控制台的错误
Uncaught TypeError: Cannot read property 'onHandleDeletion' of undefined
at Object.onHandleDeletion (index.js:497)
at onClick (Supervisor.js:24)
at HTMLUnknownElement.callCallback (react-dom.development.js:100)
at Object.invokeGuardedCallbackDev (react-dom.development.js:138)
at Object.invokeGuardedCallback (react-dom.development.js:187)
at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:201)
at executeDispatch (react-dom.development.js:461)
at executeDispatchesInOrder (react-dom.development.js:483)
at executeDispatchesAndRelease (react-dom.development.js:581)
at executeDispatchesAndReleaseTopLevel (react-dom.development.js:592)
at forEachAccumulated (react-dom.development.js:562)
at runEventsInBatch (react-dom.development.js:723)
at runExtractedEventsInBatch (react-dom.development.js:732)
at handleTopLevel (react-dom.development.js:4476)
at batchedUpdates$1 (react-dom.development.js:16659)
at batchedUpdates (react-dom.development.js:2131)
at dispatchEvent (react-dom.development.js:4555)
at interactiveUpdates$1 (react-dom.development.js:16714)
at interactiveUpdates (react-dom.development.js:2150)
at dispatchInteractiveEvent (react-dom.development.js:4532)
其中data是肯定可以携带数据的对象
我希望在控制台中记录数据