Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DateTimePicker] Fix where changing TimePicker clears date #1474

Merged

Conversation

cathyxz
Copy link
Contributor

@cathyxz cathyxz commented Aug 20, 2017

Fixes #1402

Checklist

Changes proposed in this pull request:

In dateTimePicker component, we should only reset the state based on props if the props have actually changed. Otherwise, we will needless clear or reset DateTimePicker state based on props that have not changed.

Reviewers should focus on:

Screenshot

bugfix


This change is Reviewable

@palantirtech
Copy link
Member

Thanks for your interest in palantir/blueprint, @cathyxz! Before we can accept your pull request, you need to sign our contributor license agreement - just visit https://cla.palantir.com/ and follow the instructions. Once you sign, I'll automatically update this pull request.

@cathyxz cathyxz force-pushed the cathyxz/date-time-picker-example-select branch 2 times, most recently from 586f857 to 4f0d544 Compare August 20, 2017 23:56
@giladgray
Copy link
Contributor

Thanks @cathyxz! Would you be able to add a unit test that asserts the bug is fixed? Like, changing time props should not reset date.

@cathyxz cathyxz changed the title Fix Docs DateTimePicker example where changing TimePicker clears date [DatePicker] Fix Docs DateTimePicker example where changing TimePicker clears date Aug 21, 2017
@giladgray giladgray changed the title [DatePicker] Fix Docs DateTimePicker example where changing TimePicker clears date [DateTimePicker] Fix where changing TimePicker clears date Aug 21, 2017
Copy link
Contributor

@cmslewis cmslewis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Left a small request.

} else {
// clear only the date to remove the selected-date style in the calendar
this.setState({ dateValue: null });
if (this.props.value !== nextProps.value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: would prefer this structure to avoid nesting everything so much:

if (this.props.value === nextProps.value) {
    return;
} else if (nextProps.value != null) {
    // ....
} else {
    // ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually like it better too...

@cathyxz cathyxz force-pushed the cathyxz/date-time-picker-example-select branch from 4f0d544 to 4e2f2e4 Compare August 22, 2017 05:31
@giladgray
Copy link
Contributor

@cathyxz case in point for why you should not force-push: try to click the filename for chris' comment above and you'll see a sad github page. https://github.com/palantir/blueprint/pull/1474/files/4f0d54473b9647c02915d9270b66403fb06f8256

@giladgray
Copy link
Contributor

also @cathyxz can we get that unit test?

@cathyxz
Copy link
Contributor Author

cathyxz commented Aug 22, 2017

I added a unit test, but I'm not too sure now about this being the correct fix.

What I did with DateTimePicker was essentially to say that if you pass in the same prop twice, that should not result in a change of state.

Since @cmslewis wrote logic to ensure that passing a null or undefined value clears the selected date, I'm not actually sure whether we should fix the DateTimePicker or the usage of it in our DateTimePickerExample. DateTimePickerExample is kind of weird in the sense that it does not pass a value prop, thus value here defaults to undefined. Usually if you are controlling the DateTimePicker, I imagine you would want to control the value. For example, an equally effective fix for the original problem would be to pass in state.date from the DateTimePickerExample as value. This would entail something more along the lines of a docs clarification. Basically to require that if you pass in an onChange, then you also have to manage the value?

Copy link
Contributor

@giladgray giladgray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this behavior seems correct to me? the if / else if / else pattern helps a lot. we must continue to support uncontrolled usage, which necessarily entails supporting onChange without value to simply listen to interactions. this is a standard React pattern.

it("Passing the same value prop twice does not clear the selected date", () => {
const { root, getSelectedDay } = wrap(<DateTimePicker />);
assert.isTrue(getSelectedDay().exists());
root.setProps({ value: undefined });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would be much clearer to use an actual value and pass it on line 105 too.
<DateTimePicker value={VALUE} />

Copy link
Contributor Author

@cathyxz cathyxz Aug 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that does not test the same thing. I think it is more appropriate to change the name of this test to reflect what it's really testing (which I did). So the DateTimePicker only selects its own date and time if the value prop is undefined. What we are trying to fix here is given that a user implements onChange but does NOT pass in a value, we want to avoid the onChange handler, which will pass in new props, to interfere with / clear out the date/time state managed by the DateTimePicker.

For example, this test should fail:

 it("Passing the same value prop twice does not change a user-selected date", () => {
            const value = new Date(2012, 2, 5, 6, 5, 40);
            const { root, getDay } = wrap(<DateTimePicker value={value} />);
            assert.strictEqual(root.state("dateValue"), value);
            
            getDay(15).simulate("click");

            const modifiedDate = new Date(2012, 2, 15, 6, 5, 40);
            assert.strictEqual(root.state("dateValue"), modifiedDate); // this will fail because DateTimePicker no longer manages state since value is defined
            
            root.setProps({ value: value });
            assert.strictEqual(root.state("dateValue"), modifiedDate);
 });

@giladgray
Copy link
Contributor

😄 if you're worried about incorrect behavior, write more unit tests! 🏫

@@ -8,7 +8,6 @@
import { assert } from "chai";
import { mount } from "enzyme";
import * as React from "react";

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this newline in place to differentiate external dependencies from internal dependencies.

assert.isNotNull(root.state("dateValue"));
assert.isTrue(getSelectedDay().exists());
});

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this trailing newline

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 newline is legit now that there's a second test

@@ -116,4 +124,5 @@ describe("<DateTimePicker>", () => {
root,
};
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Delete this trailing newline

@cathyxz
Copy link
Contributor Author

cathyxz commented Aug 26, 2017

@cmslewis I think we're gtg here, but obviously welcome any more feedback and comments.

@cathyxz cathyxz force-pushed the cathyxz/date-time-picker-example-select branch from 9aef29c to 6ebd753 Compare August 29, 2017 03:34
@cmslewis cmslewis merged commit 3eb4b27 into palantir:master Aug 30, 2017
@cmslewis
Copy link
Contributor

I'll try to add this to the release.

cmslewis pushed a commit that referenced this pull request Aug 30, 2017
* Fixes #1402 time picker change clears data picker

* Add unit test to verify passing the same prop twice does not change the selected date

* Change unit test name to be more accurate

* Delete extra whitespace and newlines

* Add unit test for rerendering with undefined value prop
cmslewis added a commit that referenced this pull request Aug 30, 2017
@cmslewis cmslewis mentioned this pull request Aug 30, 2017
cmslewis added a commit that referenced this pull request Aug 30, 2017
* Prepare Release 1.27.0

* Revert @blueprintjs/core dependency versions in site-landing/ and docs/

* [DateTimePicker] Fix where changing TimePicker clears date (#1474)

* Fixes #1402 time picker change clears data picker

* Add unit test to verify passing the same prop twice does not change the selected date

* Change unit test name to be more accurate

* Delete extra whitespace and newlines

* Add unit test for rerendering with undefined value prop

* Incorporate datetime PR #1474
@cathyxz cathyxz deleted the cathyxz/date-time-picker-example-select branch August 6, 2018 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants