Blueprint: DateInput: entering bad date blows up entire page

Created on 11 Mar 2019  路  9Comments  路  Source: palantir/blueprint

If i type a badly formed date into DateInput the whole page goes white.

in come cases, it detects bad date and makes the input border red. in other cases it blows up entire page

              <DateInput
                    formatDate={date => date.toLocaleDateString()}
                    parseDate={str => new Date(str)}
                    onChange={(newDate) => {r.endDate = newDate; this.updateRestriction(r) }}
                    inputProps={{ leftIcon: "calendar" }}
                    placeholder={"as of M/D/Y"} value={r.endDAte}>
                </DateInput>

errors:

Uncaught Error: [Blueprint] <DatePicker> value prop must be within minDate and maxDate bounds.
    at DatePicker.validateProps (datePicker.js:215)
    at DatePicker.AbstractPureComponent.componentWillReceiveProps (abstractPureComponent.js:48)
    at DatePicker.componentWillReceiveProps (datePicker.js:173)
    at callComponentWillReceiveProps (react-dom.development.js:11826)
    at updateClassInstance (react-dom.development.js:12039)
    at updateClassComponent (react-dom.development.js:15071)
    at beginWork (react-dom.development.js:16064)
    at performUnitOfWork (react-dom.development.js:20084)
    at workLoop (react-dom.development.js:20125)
    at HTMLUnknownElement.callCallback (react-dom.development.js:147)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
    at invokeGuardedCallback (react-dom.development.js:250)
    at replayUnitOfWork (react-dom.development.js:19308)
    at renderRoot (react-dom.development.js:20238)
    at performWorkOnRoot (react-dom.development.js:21162)
    at performWork (react-dom.development.js:21072)
    at performSyncWork (react-dom.development.js:21046)
    at interactiveUpdates$1 (react-dom.development.js:21331)
    at interactiveUpdates (react-dom.development.js:2268)
    at dispatchInteractiveEvent (react-dom.development.js:5086)
DatePicker.validateProps @ datePicker.js:215
AbstractPureComponent.componentWillReceiveProps @ abstractPureComponent.js:48
DatePicker.componentWillReceiveProps @ datePicker.js:173
callComponentWillReceiveProps @ react-dom.development.js:11826
updateClassInstance @ react-dom.development.js:12039
updateClassComponent @ react-dom.development.js:15071
beginWork @ react-dom.development.js:16064
performUnitOfWork @ react-dom.development.js:20084
workLoop @ react-dom.development.js:20125
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
replayUnitOfWork @ react-dom.development.js:19308
renderRoot @ react-dom.development.js:20238
performWorkOnRoot @ react-dom.development.js:21162
performWork @ react-dom.development.js:21072
performSyncWork @ react-dom.development.js:21046
interactiveUpdates$1 @ react-dom.development.js:21331
interactiveUpdates @ react-dom.development.js:2268
dispatchInteractiveEvent @ react-dom.development.js:5086
index.js:1446 The above error occurred in the <Blueprint3.DatePicker> component:
    in Blueprint3.DatePicker (created by Blueprint3.DateInput)
    in div (created by Blueprint3.DateInput)
    in div (created by InnerPopper)
    in div (created by InnerPopper)
    in Blueprint3.ResizeSensor (created by InnerPopper)
    in div (created by InnerPopper)
    in InnerPopper (created by Context.Consumer)
    in Popper (created by Blueprint3.Popover)
    in Transition (created by CSSTransition)
    in CSSTransition (created by Blueprint3.Overlay)
    in div (created by TransitionGroup)
    in TransitionGroup (created by Blueprint3.Overlay)
    in Blueprint3.Portal (created by Blueprint3.Overlay)
    in Blueprint3.Overlay (created by Blueprint3.Popover)
    in span (created by Blueprint3.Popover)
    in Manager (created by Blueprint3.Popover)
    in Blueprint3.Popover (created by Blueprint3.DateInput)
    in Blueprint3.DateInput (at Restrictions.tsx:141)
    in td (at Restrictions.tsx:184)
    in tr (at Restrictions.tsx:164)
    in tbody (at Restrictions.tsx:215)
    in table (at Restrictions.tsx:202)
    in div (at Restrictions.tsx:78)
    in Restrictions (at App.tsx:14)
    in div (at App.tsx:12)
    in App (at src/index.tsx:13)

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://fb.me/react-error-boundaries to learn more about error boundaries.
function.console.(anonymous function) @ index.js:1446
logCapturedError @ react-dom.development.js:17679
logError @ react-dom.development.js:17715
update.callback @ react-dom.development.js:18738
callCallback @ react-dom.development.js:16903
commitUpdateEffects @ react-dom.development.js:16943
commitUpdateQueue @ react-dom.development.js:16933
commitLifeCycles @ react-dom.development.js:17971
commitAllLifeCycles @ react-dom.development.js:19473
callCallback @ react-dom.development.js:147
invokeGuardedCallbackDev @ react-dom.development.js:196
invokeGuardedCallback @ react-dom.development.js:250
commitRoot @ react-dom.development.js:19697
(anonymous) @ react-dom.development.js:21245
unstable_runWithPriority @ scheduler.development.js:255
completeRoot @ react-dom.development.js:21244
performWorkOnRoot @ react-dom.development.js:21167
performWork @ react-dom.development.js:21072
performSyncWork @ react-dom.development.js:21046
interactiveUpdates$1 @ react-dom.development.js:21331
interactiveUpdates @ react-dom.development.js:2268
dispatchInteractiveEvent @ react-dom.development.js:5086
react-dom.development.js:21132 Uncaught Error: [Blueprint] <DatePicker> value prop must be within minDate and maxDate bounds.
    at DatePicker.validateProps (datePicker.js:215)
    at DatePicker.AbstractPureComponent.componentWillReceiveProps (abstractPureComponent.js:48)
    at DatePicker.componentWillReceiveProps (datePicker.js:173)
    at callComponentWillReceiveProps (react-dom.development.js:11826)
    at updateClassInstance (react-dom.development.js:12039)
    at updateClassComponent (react-dom.development.js:15071)
    at beginWork (react-dom.development.js:16064)
    at performUnitOfWork (react-dom.development.js:20084)
    at workLoop (react-dom.development.js:20125)
    at renderRoot (react-dom.development.js:20205)
    at performWorkOnRoot (react-dom.development.js:21162)
    at performWork (react-dom.development.js:21072)
    at performSyncWork (react-dom.development.js:21046)
    at interactiveUpdates$1 (react-dom.development.js:21331)
    at interactiveUpdates (react-dom.development.js:2268)
    at dispatchInteractiveEvent (react-dom.development.js:5086)
datetime question

Most helpful comment

if i set only the formatDate and parseDate input the DateInput make the entire page crash if i set an out of range date... you should reopen this

All 9 comments

You must do your own validation of the typed input if you're using the component in a controlled manner like this. See the last part of the value prop documentation:

image

if i set only the formatDate and parseDate input the DateInput make the entire page crash if i set an out of range date... you should reopen this

@adidahiya thanks for the replies, but why it's closed?
Look this example: if minDate is not defined (and used default 20 years in the past) and user typed manually for example, wrong value with year of 200 in the past, then next lines of code will just throw uncaught exception into the runtime:

if (value != null && !DateUtils.isDayInRange(value, [minDate, maxDate])) {
  throw new Error(Errors.DATEPICKER_VALUE_INVALID);
}

1) Okay, there was an error, but it will blows up runtime at all. I believe crashing up the page in 2019 is not a good practice at all.
But the question is how to catch up this without any restriction of min\max dates? Maybe am I doiing something wrong or misunderstanding?
2) Why onError callback doesn't fires in this case? For what the cases this callback serves?

@nickensoul similar to https://github.com/palantir/blueprint/issues/3394, can you provide a repro in a code sandbox? I think we could continue discussion there.

You can catch the error with React error boundaries. Or you can do the validation inside parseDate -- check if the parsed value is inside the range and set the controlled date value accordingly.

I think there is some confusion on this issue. It's actually quite simple, at least in the form I am encountering it. Fundamentally, if you use a DateInput in a controlled fashion, you are all but guaranteed that it will crash your page during development if you try to type into it. I know this check doesn't occur in production, but it makes it impossible to test invalid inputs (or even test typing into the control) without building a production release.

As @nickensoul points out above, the validation check here will crash the page if there is ever any value in the field (even while in the process of typing into the input) that isn't within the minDate/maxDate range.

I can't see how this check is helpful to the developer. Fundamentally, the point of value is to use this as a controlled input, so an invalid value doesn't come from the developer, it comes from the user. My recommendation is just to remove it. I'm happy to submit a PR to remove those three lines if @adidahiya and other folks here agree.

EDIT: I realize I am doing something a bit unusual here -- I am using the onChange callback from the input field itself (in inputProps) to trigger the update of the value. If you don't do that, you can type whatever you want in the field and it doesn't crash unless you hit enter. However, I think my point still stands that this check is not useful.

I am using the onChange callback from the input field itself (in inputProps) to trigger the update of the value.

@michael-swarm can you explain a bit more why you need to do this instead of using DateInput's onChange? Sounds like the component is (understandably) not resilient for this unsupported use case.

Hi @adidahiya, sure, my use case is this:

  • I'm trying to use a DateInput as part of a form. I'm using another library (react-hook-form) to manage and validate the form.
  • Other fields in the form can cause the date value to change, so I need to use the component in controlled mode.
  • Whenever the user changes this date, another field needs to update to reflect the new value. It's important these fields are in sync, and that the user gets feedback on how their date change effects the other field before submission.
  • This also means that it's important that the (external) validation runs any time the date field changes.
  • This date is also optional (the user can clear the field).

I've tried to use DateInput's onChange and onError callbacks, but I ran into the following issues:

  • If the user types a valid date that is outside of the min/max date range then blurs the field, the exception in question is thrown, so it's hard to test what would happen in production. Again, this is not a developer mistake but bad input from the user. Plus, there is no way to disable these checks, which are redundant since I am validating the date external to the component.
  • If the user types something that cannot be parsed as a date at all and then blurs the field, the onError callback is called and "Invalid date" is displayed in the field, as expected. However, if I now focus the field, the "Invalid date" text is cleared, giving me an empty field. If I now blur the field without changing anything, I have an empty field (a valid value in my case) but no further callbacks have been called, resulting in an inconsistent state. Using the input field's onChange was one attempt to work around this issue, but I was updating the value as a result, which will never work, so that's my fault. :)

Revisiting component validation logic across Blueprint... I think the best thing to improve developer experience at this point would be to change the errors thrown in validateProps into console.error logs instead. Since the validation doesn't run in production, this change would allow developers test their components in a way that more closely matches what their users will see in a production build. I will make a PR soon...

Sounds great, thank you! 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shahzeb1 picture shahzeb1  路  3Comments

sunabozu picture sunabozu  路  3Comments

scottfr picture scottfr  路  3Comments

havesomeleeway picture havesomeleeway  路  3Comments

raiju picture raiju  路  3Comments