0

I have a component which renders x amount of DateInputs based on x number of charges. The date inputs should be rendered with the default value loaded from the server. Once the onChange is triggered it updates the state in the parent and prints out the console with the selected date using the computedProperty. To give more context here is an image of the page:

enter image description here

A you can see, a datepicker is rendered for each charge and the user needs the ability to modify the charge date. So in terms of data flow, the onChange in the child component triggers the method handleChargesDateChange in the parent, as the state needs to be stored in parent.

At the minute, the default charge date is rendered in the dropdown, but when onChange is executed then date input value does not change. However, the method prints out the correct date that was selected. Again, for more context, here is a screenshot of the data stored in parent when child executes onChange on the date picker.

enter image description here

As you can see, the date values get modified when the user selects one from each datepicker. However, the actual datepicker value stays the same. I can get it to work where it renders with an empty date for each datepicker and when the user selects a new date, it will render the datepicker with the selected date. It also stored the value in parent. But I am really struggling to render the defalt value, but when it is changed update the datepicker with the user selected value... I hope this makes sense.. Anyway here's the code. So the method which gets triggered in parent:

 handleChargesDateChange = (e) => {
    const date = e.target.value;
    const momentDate = moment(date);
    const chargeId = e.target.name;
    console.log(date);
    console.log(momentDate);
    this.setState({
        updatedChargeDates: [
            ...this.state.updatedChargeDates,
            {[chargeId]: date}
        ]
    }, () => console.log(this.state.updatedChargeDates))
}

This then gets passed down (around 3 children deep) via:

  <Grid.Row>
            <Grid.Column width={16}>
                <OrderSummary
                    order={this.state.order}
                    fuelTypes={this.state.fuelTypes}
                    vehicleClasses={this.state.vehicleClasses}
                    deviceTypes={this.state.deviceTypes}
                    chargeTypes={this.state.chargeTypes}
                    featureTypes={this.state.featureTypes}
                    itemGroups={this.state.itemGroups}
                    itemTypes={this.state.itemTypes}
                    updateChargeDates={this.handleChargesDateChange}
                    chargeDates={this.state.updatedChargeDates}
                />
            </Grid.Column>

I will skip the various other children components that the method gets passed to and go straight to the effected component. So the method then lands at Charges:

 export class Charges extends Component {

constructor(props) {
    super(props);

    this.state = {
        currentItem: 0,
        newDate: '',
        fields: {}
    }
}

render() {
 const {charges, chargeTypes, updateChargeDates, chargeDates} = this.props;

 console.log('Props method', charges);
 if (charges.length === 0) { return null; }

return <Form>
    <h3>Charges</h3>
    {charges.map(charge => {

        console.log(charge);
        const chargeType = chargeTypes.find(type => type.code === charge.type) || {};
        return <Grid>
            <Grid.Row columns={2}>
                <Grid.Column>
                    <Form.Input
                        key={charge.id}
                        label={chargeType.description || charge.type}
                        value={Number(charge.amount).toFixed(2)}
                        readOnly
                        width={6} />
                </Grid.Column>
                <Grid.Column>
                    <DateInput
                        name={charge.id}
                        selected={this.state.newDate}
                        ***onChange={updateChargeDates}***
                        ***value={chargeDates[charge.id] == null ? charge.effectiveDate : chargeDates[charge.id]}***
                    />
                </Grid.Column>
            </Grid.Row>
        </Grid>
    })}
    <Divider hidden />
    <br />
</Form>
}

I have highlighted the culprit code with *** to make it easier to follow. I am using a ternary type operator to determine which value to display, but it doesnt seem to update when i select a value.. I thought that from the code I have, if the initial chargeDates[charge.id] is null then we display the charge.effectiveDate which is what it is doing, but soon as I change the date i would expect chargeDates[charge.id] to have a value, which in turn should display that value...

I really hope that makes sense, im sure im missing the point with this here and it will be a simple fix.. But seems as im a newbie to react, im quite confused..

I have tride to follow the following resources but it doesnt really give me what I want:

Multiple DatePickers in State

Daepicker state

If you need anymore questions or clarification please do let me know!

Alexander Dunn
  • 123
  • 4
  • 22
  • 3
    how about build codesandbox or stackblitz with demo of the problem? It is much easy to help when problem is reduced something as simple as possible. Have you used codesandbox? – happyZZR1400 Feb 17 '20 at 09:22
  • it is hard to debug from heree. Will you please give a shareable links where we can see and find the problems? – Md. Tazbir Ur Rahman Bhuiyan Feb 17 '20 at 09:26
  • Which library do you use for `DateInput`? they might have different API, e.g. https://www.telerik.com/kendo-react-ui/components/dateinputs/api/DateInputChangeEvent/ would need you to use `const date = e.value` instead of `e.target.value` – Aprillion Feb 17 '20 at 14:53

1 Answers1

1

Looking at your screenshot, updatedChargeDates (chargeDates prop) is an array of objects. The array has indexes 0, 1 and 2, but you access it in the DateInput like this chargeDates[charge.id] your trying to get the data at the index 431780 for example, which returns undefined, and so the condition chargeDates[charge.id] == null ? charge.effectiveDate : chargeDates[charge.id], will always return charge.effectiveDate.

You can fix this in handleChargesDateChange by making updatedChargeDates an object, like this :

 handleChargesDateChange = (e) => {
    const date = e.target.value;
    const momentDate = moment(date);
    const chargeId = e.target.name;
    console.log(date);
    console.log(momentDate);
    this.setState({
        updatedChargeDates: {
            ...this.state.updatedChargeDates,
            [chargeId]: date
        }
    }, () => console.log(this.state.updatedChargeDates))
}
Mohamed Ramrami
  • 12,026
  • 4
  • 33
  • 49
  • Thanks so much, you have no idea how much time i have spent looking at this!! I knew it would be something small :( Thanks! – Alexander Dunn Feb 19 '20 at 14:41