Search code examples
reactjsreact-nativereact-native-datetimepicker

Allowing Null Value for React-Native-DateTimePicker


I have a React Native application with a form for entering data. One of the fields is a DateTime value, but is optional. In other words, the user can choose a date if they want one, but can leave it blank/null if the field is not relevant.

However, when I assign null to the date prop of the DateTimePicker, I get an exception that null is not an object. How can allow the user to choose a date if they want to, but leave it "null" if they don't want a date in that field.

     <DateTimePicker
      isVisible={isDatePickerVisible}
      mode={mode}
      onConfirm={handleConfirm}
      onCancel={hideDatePicker}
      date={selectedDate}
      onBlur={onBlur}
    />

Is there a property I am missing? Is there a different component I can use to accomplish this?


Solution

  • Thank you to @david-scholz for the insight into the react-native-datetimepicker library and the lack of null support. With that said, his answer doesn't provide the functionality requested.

    I manage to implement it with a custom component which wraps the react-native-modal-datetimepicker library. The basic idea is to use the picker only when the user wants to pick a date.

    To accomplish this:

    1. text is used to display the current value or "No Date Selected".
    2. When the user clicks the text, the date time picker is shown to let them select a date
    3. There is a button to click if the user wants to clear the date and go back to null

    Note: This was intended to be used with Formik (in my use case) so the date / time value being passed back is in string format (it works better with Formik).

    Here is the code, in case anyone can use it. It should be considered MIT License.

    import React, { useState } from 'react';
    import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
    import DateTimePickerModal from 'react-native-modal-datetime-picker';
    import moment from 'moment';
    
    const isNullOrWhitespace = ( input ) => {
      return !input || !input.trim();
    }
    
    export default function NullableDatePicker (props) {
        const {value, onChange, onBlur} = props;
        const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
        const [selectedDate, setSelectedDate] = useState(isNullOrWhitespace(value) ?  new Date() : new Date(value));
        const [hasDate, setHasDate] = useState(isNullOrWhitespace(value) ? false : true);
    
        const showDatePicker = () => {
          setDatePickerVisibility(true);
        };
      
        const hideDatePicker = () => {
          setDatePickerVisibility(false);
        };
      
        const handleConfirm = date => {
          hideDatePicker();
          setHasDate(true);
          setSelectedDate(new Date(date));  
          onChange(valueToString(date));
        };
      
        const valueToString = selectedDate => {
            return moment(selectedDate).format('YYYY-MM-DD');
        }
    
        const clearDate = () => {
            setHasDate(false);
            onChange('');
        }
      
        return (
          <View>
            <View style={styles.fixToText}>
            <Text style={styles.dateText} onPress={showDatePicker}>{hasDate ? valueToString(selectedDate) : 'No Date Selected'}</Text>
            <Text>   </Text>
            <TouchableOpacity 
                title="Clear"
                onPress={() => clearDate()}
                disabled={!hasDate}
                style={styles.button}
            >
               <Text>Clear</Text> 
            </TouchableOpacity>
            </View>
            <DateTimePickerModal
              isVisible={isDatePickerVisible}
              mode='date'
              onConfirm={handleConfirm}
              onCancel={hideDatePicker}
              date={selectedDate}
              onBlur={onBlur}
            />
          </View>
        );  
      }
      const styles = StyleSheet.create(
          {
            fixToText: {
                flexDirection: 'row'
            },
            button: {
                alignItems: "center",
                backgroundColor: "lightblue",
                padding: 5,
                height: 30,
                width: 50
            },
            dateText:{
                height: 30,
                textAlignVertical: 'center'
            }
          }
      )