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

fix(text-field): disable validation check in setRequired #2201

Merged
merged 58 commits into from
Mar 2, 2018

Conversation

moog16
Copy link
Contributor

@moog16 moog16 commented Feb 6, 2018

resolves #2029

@codecov-io
Copy link

codecov-io commented Feb 6, 2018

Codecov Report

Merging #2201 into master will increase coverage by 0.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2201      +/-   ##
==========================================
+ Coverage   98.84%   98.85%   +0.01%     
==========================================
  Files         100      100              
  Lines        4075     4115      +40     
  Branches      524      526       +2     
==========================================
+ Hits         4028     4068      +40     
  Misses         47       47
Impacted Files Coverage Δ
packages/mdc-textfield/index.js 94.8% <100%> (+1.41%) ⬆️
packages/mdc-textfield/foundation.js 98.85% <100%> (+0.04%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update c14d244...fe82837. Read the comment docs.

@@ -139,7 +139,7 @@ <h2>Password field with validation</h2>
<h2>Outlined Text Field</h2>
<div id="demo-tf-outlined-wrapper">
<div id="tf-outlined-example" class="mdc-text-field mdc-text-field--outlined" data-demo-no-auto-js>
<input required pattern=".{8,}" type="text" id="tf-outlined-input" class="mdc-text-field__input"
<input pattern=".{8,}" type="text" id="tf-outlined-input" class="mdc-text-field__input"
Copy link
Contributor

Choose a reason for hiding this comment

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

This line is inconsistent with the JS code below (pattern would be .{8,} when required, but .* when not)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes you're correct. I'll sift through the rest of the file and make sure that all works the same.

@@ -301,9 +301,6 @@ class MDCTextFieldFoundation extends MDCFoundation {
*/
setRequired(isRequired) {
this.getNativeInput_().required = isRequired;
// Addition of the asterisk is automatic based on CSS, but validity checking
Copy link
Contributor

Choose a reason for hiding this comment

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

This solution is problematic, because it also leaves things as marked invalid if you change required from true to false... in which case they're no longer invalid if empty. At the very least I think we should still be calling styleValidity if isRequired is false.

Also, I think in the original issue you talked about distinguishing between whether the field was "dirty" or not. I'm not sure if we even have a check for that, though I think what you really mean is whether the input has ever received focus? This solution would just never update the state at all when turning required on.

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 did notice your concern in the demo, and I did talk to Dave about that. In both cases the input is still marked as invalid (with or w/o styleValidity call). In the Text Field box example, this can be fixed by setting input.pattern before setting input.required. I thought having to do that was fragile.

This then led me to question why do we choose to manage required in foundation when HTML5 already does this for us? I see required as a just another piece of validation, meaning why aren't we managing pattern, minlength, etc. Having to manage all of those properties isn't reasonable, so why do we only choose required?

Copy link
Contributor

Choose a reason for hiding this comment

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

Huh... you're right, even now on the demo page in 0.30.0 it doesn't clear the invalid style when setting required back to false, which seems like a problem... and that particular example doesn't even use pattern at all.

HTML5 marks a field as invalid immediately if it is required and blank, which is user-unfriendly and something we're specifically avoiding doing, right? Though I suppose the same is true with pattern if the text input is initially populated, but AFAICT pattern isn't applying :invalid if the field is blank...

https://codepen.io/kfranqueiro/pen/yvgjGb

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Interesting...I didn't realize the invalid attribute is added. We aren't using :invalid to style invalid state, which is why we don't see this in the demos. In @williamernest's (codepen)[https://codepen.io/williamernest/pen/ddPdxo] we can see the current behavior and the HTML5 behavior, which is what this fix is trying to achieve.

Do you have any thoughts as to just removing setRequired and get required?

Copy link
Contributor

Choose a reason for hiding this comment

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

In Will's demo, setting JS required from true to false properly clears the invalid state, reinforcing my original point that I think we should preserve the current logic specifically when setting required to false.

I made my codepen using pure HTML5 because I thought when you said "HTML5 already does this for us" you were referring to OOTB native behavior, not the behavior of our component WRT that attribute. I thought Will was originally only modifying the HTML5 attribute directly with our JS component as a workaround to avoid surfacing this bug in the demo anyway; I'm not sure it's something we should be actively comparing behavior to or seeking to match, since the JS component maintains state itself and setting the attribute directly skips that logic.

Ultimately I don't think we can remove the required setter/getter, given the problem regarding the input still being marked as invalid after it is no longer required. I also don't think we want to rely on the native HTML5 behavior directly rather than set our own class, since as I said above, generally users find that behavior undesirable because fields should not be highlighted as invalid before the user ever interacts with them.

Copy link
Contributor Author

@moog16 moog16 Feb 9, 2018

Choose a reason for hiding this comment

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

I don't think Will's codepen is a common use case, but I suppose that doesn't mean we shouldn't design for it. Having the styleValidity call in setRequired is what is causing the original issue. Are you suggesting that developers use the HTML5 attr directly instead of our JS setter/getter if they see this issue?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm suggesting pretty much the opposite of that... We need to fix the programmatic API so that it works correctly in both directions (required -> not, not -> required) and developers should not ever have reason to programmatically toggle the HTML attribute directly on a JS text field. (It should work if the HTML attribute is initially set in markup though.)

Currently in our component on master, IIUC, required -> not works correctly programmatically, but not -> required doesn't. In the PR in its current state, the opposite is true. We want both to work.

If this needs further clarification, I will try to respond off-github.

setupValueTest('', /* isValid */ false);

foundation.setRequired(true);
assert.isOk(foundation.isRequired());
td.verify(mockAdapter.addClass(cssClasses.INVALID));
Copy link
Contributor

Choose a reason for hiding this comment

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

If we don't have a negative test for this (testing from required=true to required=false) we should probably add one (see my comment above).

Matty Goo added 2 commits February 8, 2018 13:04
BREAKING CHANGE: removed setRequired and isRequired from foundation. Removed get/set required from component.
@moog16
Copy link
Contributor Author

moog16 commented Feb 10, 2018

After much debate offline, the decision was made to remove set/get required from the component and remove isRequired and setRequired from foundation, and instead use a generic getValidationAttribute, setValidationAttribute and removeValidationAttribute. This will allow for other validation properties than just required. In our demo pages exists pattern and minlength which illustrate the benefit to this. This will also future proof the text-field if any new HTML validation attributes are added to the spec.

When either removeValidationAttribute or setValidationAttribute are invoked, it will set the validation styles to valid regardless of value. If any validation attributes are toggled on/off, the user should be given a chance to interact with the text-field before seeing errors.

*/
get required() {
return this.foundation_.isRequired();
getValidationAttribute(attrName) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would still expect this to be exposed via required / pattern / etc. setters/getters on the component to make it match working with a native input element?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

are you saying keep get/set required, but also add get/set pattern that proxy to foundation_.getValidationAttribute and foundation_.setValidationAttribute? Should we add others eg. minlength, maxlength?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, that's what I was thinking, and yes to min/maxlength too.

Matt Goo added 2 commits February 23, 2018 11:27
BREAKING CHANGE: removed isRequired and setRequired from text-field foundation
@@ -1368,9 +1368,9 @@
"integrity": "sha1-+GzWzvT1MAyOY+B6TVEvZfv/RTE=",
"dev": true,
"requires": {
"JSONStream": "1.3.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure how package-lock suddenly found its way into this PR but it doesn't need to be here

assert.equal(component.maxLength, 10);
component.maxLength = -1;
// IE11 has a different value for no maxlength property
assert.isFalse(component.maxLength === 10);
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: assert.notEqual(component.maxLength, 10)

@kfranqueiro
Copy link
Contributor

Also just noticed a bug: the helper text element below Text Field Box seems to initially be visible even though the checkbox is initially unchecked. This doesn't seem to be a problem with the first example on the page.

@moog16
Copy link
Contributor Author

moog16 commented Feb 23, 2018

Yes looks like it initially needs style='none'. I'll add it inline, since the checkbox toggles it on/off.

Copy link
Contributor

@kfranqueiro kfranqueiro left a comment

Choose a reason for hiding this comment

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

For some reason I'm not seeing helper text on the Text Field Box example when Use Helper Text is checked and I focus the input? This is inconsistent with the first example where helper text appears on focus. The "Make helper text persistent" seems to work though.

@moog16
Copy link
Contributor Author

moog16 commented Feb 27, 2018

It seems that Text Field Box is only used as a validation message, which is not given opacity: 1 when focused on. I'll add the the Use helper text as validation message checkbox to make it consistent with the top text field.

/**
* Disconnect all validation attribute listeners on the input element.
*/
deregisterValidationAttributeChangeHandler() {}
Copy link
Contributor

Choose a reason for hiding this comment

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

This should probably just disconnect a specific observer that it is handed, and we should loop within the component's destroy method instead of building the iteration logic into the adapter.

/**
* Registers a validation attribute change listener on the input element.
* @return {!MutationObserver}
* @param {function(!Array): undefined} handler
Copy link
Contributor

Choose a reason for hiding this comment

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

Put @param before @return

* Handles validation attribute changes
* @param {Array<MutationRecord>} mutationsList
*/
handleValidationAttributeMutation(mutationsList) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm inclined to think this should be a @private method with underscore suffix. No one should ever publicly need to call this, since we're hooking up the mutation observer via adapter APIs and that will call it.

});

test('#destroy removes event listeners', () => {
const {foundation, mockAdapter} = setupTest();
foundation.validationObserver_ = {test: 'test1'};
Copy link
Contributor

Choose a reason for hiding this comment

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

This can just be {}

@moog16 moog16 merged commit 0ba7d10 into master Mar 2, 2018
@moog16 moog16 deleted the fix/text-field/validation-behave-like-html5 branch March 2, 2018 16:33
acdvorak added a commit that referenced this pull request Mar 8, 2018
commit f17e0d3
Author: Will Ernest <[email protected]>
Date:   Thu Mar 8 13:20:48 2018 -0500

    fix(text-field): Clicking label should focus textfield (#2353)

commit 77b15f4
Author: Bonnie Zhou <[email protected]>
Date:   Wed Mar 7 16:29:57 2018 -0800

    refactor(button): Remove compact variant (#2361)

    BREAKING CHANGE: The compact variant of MDC Button is removed.

commit 35a5cfc
Author: Will Ernest <[email protected]>
Date:   Tue Mar 6 19:54:23 2018 -0500

    fix(toolbar): Fix colors for svg icons. Update custom-toolbar demo (#2331)

    SVG icons in the toolbar will now use the same color as the font icons.

commit dc52201
Author: Andrew C. Dvorak <[email protected]>
Date:   Tue Mar 6 16:00:12 2018 -0800

    fix(theme): Move @alternate annotations for Closure Stylesheets (#2355)

    `@alternate` annotations need to come before the _second_ property. Otherwise, Closure Compiler strips the first property (it does not output it at all).

commit 3c04419
Author: aprigogin <[email protected]>
Date:   Tue Mar 6 14:29:12 2018 -0800

    fix(button): icon in rtl should have margin right flipped. (#2346)

commit b9000a4
Author: Cory Reed <[email protected]>
Date:   Tue Mar 6 07:37:40 2018 -0800

    fix(demos): Correct RTL/LTR toggling in demos in Safari (#2348)

commit ab85736
Author: Andrew C. Dvorak <[email protected]>
Date:   Mon Mar 5 19:00:11 2018 -0500

    fix: Use `var` instead of `const` in menu demo (#2345)

    Safari 9.x and IE 10 do not support `const`

commit dc3d69f
Author: aprigogin <[email protected]>
Date:   Mon Mar 5 15:22:31 2018 -0800

    fix(rtl): Adding noflip annotations to fix downstream rtl issues (#2344)

    * fix(rtl): Adding noflip annotations to fix downstream rtl issues

    * fix(rtl): remove changes to button, will be in separate PR

    * fix(rtl): remove changes to button, will be in separate PR - second attempt.

    * fix(rtl): removed extra whitespace

commit eb4138e
Author: Patrick RoDee <[email protected]>
Date:   Mon Mar 5 14:10:46 2018 -0800

    docs: Update CHANGELOG.md

commit f478610
Author: Patrick RoDee <[email protected]>
Date:   Mon Mar 5 14:10:30 2018 -0800

    chore: Publish

commit 78408bb
Author: Andrew C. Dvorak <[email protected]>
Date:   Mon Mar 5 16:13:02 2018 -0500

    fix: Use `var` instead of `const` in demos/ready.js (#2343)

    Safari 9.x and IE 10 do not support `const`, and `ready.js` is not transpiled to ES5.

commit 49a9449
Author: Will Ernest <[email protected]>
Date:   Mon Mar 5 12:21:54 2018 -0500

    chore(select): Fix JS example in Readme (#2332)

commit bc17291
Author: Will Ernest <[email protected]>
Date:   Fri Mar 2 13:21:07 2018 -0500

    feat(top app bar): Add short top app bar always collapsed feature (#2327)

commit 0ba7d10
Author: Matty Goo <[email protected]>
Date:   Fri Mar 2 11:33:19 2018 -0500

    fix(text-field): disable validation check in setRequired (#2201)

    BREAKING CHANGE: removed setRequired and isRequired from foundation.

commit c14d244
Author: Will Ernest <[email protected]>
Date:   Fri Mar 2 10:37:18 2018 -0500

    chore(select): Fix ID values in demo (#2330)

    Remove unused ID and changed duplicated ID values. Also fixed the parentheses in RTL.

commit ecf4060
Author: Bonnie Zhou <[email protected]>
Date:   Thu Mar 1 16:38:41 2018 -0500

    feat(chips): Change chip color when selected (#2329)

    BREAKING CHANGE: The `mdc-chip--activated` class, `mdc-chip-activated-ink-color` Sass mixin, and the `toggleActive` methods on `MDCChip`/`MDCChipSet` have been renamed to `mdc-chip--selected`, `mdc-chip-selected-ink-color`, and `toggleSelected`, respectively.

commit 4b24b51
Author: Matty Goo <[email protected]>
Date:   Wed Feb 28 15:20:19 2018 -0500

    chore(floating-label): separate label module from text-field (#2237)

    BREAKING CHANGE: must use `.mdc-floating-label` selector instead of `.mdc-text-field__label`

commit fd8d8d9
Author: Will Ernest <[email protected]>
Date:   Wed Feb 28 14:21:55 2018 -0500

    feat(top-app-bar): Implement short top app bar (#2290)

    Adds the short top app bar variant to the top app bar.

commit a9f9bf2
Author: Kenneth G. Franqueiro <[email protected]>
Date:   Wed Feb 28 13:06:41 2018 -0500

    docs(select): Fix front matter for label sub-component (#2323)
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.

Text-field: Setting required with Component causes field to immediately be invalid.
3 participants