React-native-modal-datetime-picker: Multiple Date / Time Pickers.

Created on 12 Sep 2017  路  2Comments  路  Source: mmazzarolo/react-native-modal-datetime-picker

I want dynamic multiple date / time pickers.
I tried a piece of code but every time I datepicker is open for some other item and not the one clicked.

Versions
react-native 0.47.1
react-native-modal-datetime-picker ^4.11.0

Code

import React, { Component } from 'react';
import {
  Text, View, StyleSheet, TouchableOpacity
} from 'react-native';
import {
  Tile as ShoutemTile, Text as ShoutemText, Title as ShoutemTitle,
  Row as ShoutemRow, Subtitle as ShoutemSubtitle, Button as ShoutemButton,
  Icon as ShoutemIcon
} from '@shoutem/ui';
import { Content, Left, Right, Body, Button, Icon, List, ListItem } from 'native-base';
import Moment from 'moment';
import DateTimePicker from 'react-native-modal-datetime-picker';
import * as utils from '../../utils';
import { Loader, CustomDialog } from '../../components/common';

export default class OfferForm extends Component {
  constructor(props) {
    Moment.locale('en');
    super(props);
    this.state = {
      offer_name: this.props.offer_name,
      offer_id: this.props.offer_id,
      form: this.props.form,
      color: this.props.color,
      isProcessing: false,
      showFinished: false,
      error: false,
      successMessage: '',
      isDateTimePickerVisible: false
    };
    for (let i = 0; i < this.state.form.length; i++) {
      this.state[this.state.form[i].id] = null;
    }
    this.confirm = this.confirm.bind(this);
    this.cancel = this.cancel.bind(this);
  }

  confirm() {
    // Send request to server
    this.setState({ isProcessing: true });
    utils
      .requestConference(this.state.selectedItems)
      .then(res => {
        try {
          this.setState({ isProcessing: false });
          if (res.status) {
            if (res.status === 'success') {
              this.setState({
                successMessage: res.message,
                showFinished: true
              });
            } else {
              this.setState({
                successMessage: res.message,
                error: true,
                showFinished: true
              });
            }
          }
        } catch (error) {
          console.log(error);
        }
      });
  }

  cancel = () => this.popupDialog.dismiss();

  showDateTimePicker = () =>
    this.setState({ isDateTimePickerVisible: true })

  hideDateTimePicker = () =>
    this.setState({ isDateTimePickerVisible: false })

  handleDatePicked = (id, type, date) => {
    let value;
    if (type === 'date') {
      value = Moment(date).format('DD MMM YYYY').toString();
    } else {
      value = Moment(date).format('hh:mm A').toString();
    }
    this.setState({
      [id]: value
    });
    console.log(this.state);
    this.hideDateTimePicker();
  };

  render() {
    const form = this.state.form;
    if (this.state.loading) {
      return (
        <Loader text='Please wait...' color={this.state.color} />
      );
    } else if (this.state.isProcessing) {
      return (
        <Loader text='Sending request...' color={this.state.color} />
      );
    } else if (this.state.showFinished) {
      return (
        <CustomDialog
          title='Thank You'
          error={this.state.error}
          message={this.state.successMessage}
          color={this.state.color}
        />
      );
    }
    const uiElements = [];
    for (let i = 0; i < form.length; i++) {
      // Define type
      let formType;
      if (form[i].type === 'date') {
        formType = (
          <ShoutemRow key={form[i].id + (2 * (i + 1))}>
            <ShoutemButton
              onPress={this.showDateTimePicker}
              style={{
                flex: 1,
                borderColor: 'grey',
                borderWidth: 1,
                borderRadius: 3,
                padding: 5,
                justifyContent: 'flex-start'
              }}
            >
              <ShoutemIcon name="add-event" style={{ color: 'grey' }} />
              <Text style={{ color: 'grey' }}>
                {this.state[form[i].id]}
              </Text>
            </ShoutemButton>
            <DateTimePicker
              key={form[i].id}
              date={new Date()}
              mode={'date'}
              isVisible={this.state.isDateTimePickerVisible}
              onConfirm={this.handleDatePicked.bind(this, form[i].id, 'date')}
              onCancel={this.hideDateTimePicker}
            />
          </ShoutemRow>
        );
      } else if (form[i].type === 'time') {
        formType = (
          <ShoutemRow key={form[i].id + (2 * (i + 1))}>
            <ShoutemButton
              onPress={this.showDateTimePicker}
              style={{
                flex: 1,
                borderColor: 'grey',
                borderWidth: 1,
                borderRadius: 3,
                padding: 5,
                justifyContent: 'flex-start'
              }}
            >
              <ShoutemIcon name="add-event" style={{ color: 'grey' }} />
              <Text style={{ color: 'grey' }}>
                {this.state[form[i].id]}
              </Text>
            </ShoutemButton>
            <DateTimePicker
              key={form[i].id}
              date={new Date()}
              mode={'time'}
              isVisible={this.state.isDateTimePickerVisible}
              onConfirm={this.handleDatePicked.bind(this, form[i].id, 'time')}
              onCancel={this.hideDateTimePicker}
            />
          </ShoutemRow>
        );
      } else if (form[i].type === 'text') {
        //
      } else if (form[i].type === 'count') {
        //
      } else if (form[i].type === 'comment') {
        //
      }
      uiElements.push(
        <ShoutemTile style={{ padding: 5 }} key={'parent_' + form[i].id + (2 * (i + 1))}>
          <ShoutemText style={{ color: '#000000' }}>{form[i].field}</ShoutemText>
          {formType}
        </ShoutemTile>
      );
    }
    return (
      <View style={{ flex: 1 }}>
        <View style={{ flex: 0.9 }}>
          <Content>
            {uiElements}
          </Content>
        </View>
        <View style={{ flex: 0.1, position: 'absolute', left: 0, right: 0, bottom: 0 }}>
          <Button
            full
            onPress={() => {
              alert('hi'); //eslint-disable-line
            }}
            style={{
              flex: 1,
              backgroundColor: this.state.color,
              borderColor: this.state.color
            }}
          >
            <ShoutemTitle style={{ color: '#FFFFFF' }}>Claim</ShoutemTitle>
          </Button>
        </View>
      </View>
    );
  }
}

question

Most helpful comment

Hello @princenaman
Given the fact that this component uses a modal, you should use only a single instance of it and simply adapt its prop to the interested values.
Just take this out of the loop:

<DateTimePicker
              key={form[i].id}
              date={new Date()}
              mode={'time'}
              isVisible={this.state.isDateTimePickerVisible}
              onConfirm={this.handleDatePicked.bind(this, form[i].id, 'time')}
              onCancel={this.hideDateTimePicker}
            />

And set the interested dates programmaticaly (keep them in the state).

For example you could change it to something like this:

showDateTimePicker = (formIdInDatePicker) =>
  this.setState({ isDateTimePickerVisible: true, formIdInDatePicker: formIdInDatePicker  })

hideDateTimePicker = () =>
  this.setState({ isDateTimePickerVisible: false, formIdInDatePicker: null })

handleDatePicked = (type, date) => {
    let value;
    if (type === 'date') {
      value = Moment(date).format('DD MMM YYYY').toString();
    } else {
      value = Moment(date).format('hh:mm A').toString();
    }
    this.setState({
      [formIdInDatePicker]: value
    });
    console.log(this.state);
    this.hideDateTimePicker();
};

...

<DateTimePicker
  date={new Date()}
  mode={'time'}
  isVisible={this.state.isDateTimePickerVisible}
  onConfirm={this.handleDatePicked.bind(this, 'time')}
  onCancel={this.hideDateTimePicker}
/>

All 2 comments

Hello @princenaman
Given the fact that this component uses a modal, you should use only a single instance of it and simply adapt its prop to the interested values.
Just take this out of the loop:

<DateTimePicker
              key={form[i].id}
              date={new Date()}
              mode={'time'}
              isVisible={this.state.isDateTimePickerVisible}
              onConfirm={this.handleDatePicked.bind(this, form[i].id, 'time')}
              onCancel={this.hideDateTimePicker}
            />

And set the interested dates programmaticaly (keep them in the state).

For example you could change it to something like this:

showDateTimePicker = (formIdInDatePicker) =>
  this.setState({ isDateTimePickerVisible: true, formIdInDatePicker: formIdInDatePicker  })

hideDateTimePicker = () =>
  this.setState({ isDateTimePickerVisible: false, formIdInDatePicker: null })

handleDatePicked = (type, date) => {
    let value;
    if (type === 'date') {
      value = Moment(date).format('DD MMM YYYY').toString();
    } else {
      value = Moment(date).format('hh:mm A').toString();
    }
    this.setState({
      [formIdInDatePicker]: value
    });
    console.log(this.state);
    this.hideDateTimePicker();
};

...

<DateTimePicker
  date={new Date()}
  mode={'time'}
  isVisible={this.state.isDateTimePickerVisible}
  onConfirm={this.handleDatePicked.bind(this, 'time')}
  onCancel={this.hideDateTimePicker}
/>

Works like a charm 馃槃

Was this page helpful?
0 / 5 - 0 ratings