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(chips): Manage chip selection for classes added manually #2391

Merged
merged 11 commits into from
Apr 6, 2018

Conversation

bonniezhou
Copy link
Contributor

Fixes #2374.

Note that if the mdc-chip--selected class was added to more than one choice chip, only the last one will be selected.

@acdvorak acdvorak self-assigned this Mar 13, 2018
@codecov-io
Copy link

codecov-io commented Mar 13, 2018

Codecov Report

Merging #2391 into master will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2391      +/-   ##
==========================================
+ Coverage   98.85%   98.85%   +<.01%     
==========================================
  Files         103      103              
  Lines        4111     4121      +10     
  Branches      516      516              
==========================================
+ Hits         4064     4074      +10     
  Misses         47       47
Impacted Files Coverage Δ
packages/mdc-chips/chip/constants.js 100% <ø> (ø) ⬆️
packages/mdc-chips/chip-set/index.js 100% <100%> (ø) ⬆️
packages/mdc-chips/chip/foundation.js 98.24% <100%> (+0.06%) ⬆️
packages/mdc-chips/chip-set/foundation.js 100% <100%> (ø) ⬆️
packages/mdc-chips/chip/index.js 78% <100%> (ø) ⬆️

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 2e7f904...3be7133. Read the comment docs.


Method Signature | Description
--- | ---
`manageSelection() => void` | Manages the selection state of the chip set, given a chip that was just selected/deselected.
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing the chip param

* @param {!Object} evt
* @private
* Manages the selection state of the chip set, given a chip that was just selected/deselected.
* @param {!MDCChip} chip
Copy link
Contributor

Choose a reason for hiding this comment

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

Will this param type be a problem for framework wrappers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a really good point, meaning that selectedChips_ should also not hold MDCChip objects.

How Text Field gets around this is having the main component hold sub-components, and pass sub-foundations to the main foundation. For example, MDCTextField has MDCTextFieldHelperText and passes MDCTextFieldHelperTextFoundation to MDCTextFieldFoundation. What do you think about doing the same here, so MDCChipSetFoundation would control MDCChipFoundation objects?

I can create a separate PR and punt this one until that gets merged.

Copy link
Contributor

Choose a reason for hiding this comment

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

NICE catch.


/**
* Handles a chip interaction event
* @param {!Object} evt
Copy link
Contributor

Choose a reason for hiding this comment

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

@param {!Event} evt

@@ -58,6 +58,14 @@ class MDCChipSet extends MDCComponent {
});
}

initialSyncWithDOM() {
Copy link
Contributor

Choose a reason for hiding this comment

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

We might want to add a test for this to prevent regressions

*/
handleChipInteraction_(evt) {
const {chip} = evt.detail;
manageSelection(chip) {
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 not wild about this method name, but I can't really think of a better alternative lol.

Maybe that's a signal that the method itself is trying to do too much, and needs to be refactored?

I also feel like in general, methods that "toggle" things tend to be error-prone and hard to use, because you always need to know the previous state before you call them.

It might be clearer and simpler to have two separate methods that are idempotent:

select(chip) {
  if (this.isChoice_()) {
    this.deselectAll_();
  }
  chip.setSelected(true);
  this.selectedChips_.push(chip);
}

deselect(chip) {
  const index = this.selectedChips_.indexOf(chip);
  if (index >= 0) {
    this.selectedChips_.splice(index, 1);
  }
  chip.setSelected(false);
}

...

isChoice_() {
  return this.adapter_.hasClass(cssClasses.CHOICE);
}

deselectAll_() {
  this.selectedChips_.forEach((chip) => {
    chip.setSelected(false);
  });
  this.selectedChips_.length = 0;
}

And the interaction handler can decide which method to call:

handleChipInteraction_(evt) {
  const {chip} = evt.detail;
  if (chip.isSelected()) {
    this.deselect(chip);
  } else {
    this.select(chip);
  }
}

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Meant to respond here earlier...
This looks great! This will also make it easier to collapse chip and chip-set into one controller, if we ever decide to do that.

@@ -44,6 +44,7 @@ test('attachTo returns an MDCChipSet instance', () => {
class FakeChip {
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be good to update the demo page so that "Choice" and "Filter" chips have an initial selection.

Copy link
Contributor

@acdvorak acdvorak left a comment

Choose a reason for hiding this comment

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

Just two small nits, otherwise LGTM!

</div>
```

To pre-select filter chips that have a leading icon, also add the class `mdc-chip__icon--hidden-leading` to the `mdc-chip__icon--leading` element. This will ensure that the checkmark displaces the leading icon.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: I think our convention has generally been mdc-chip__icon--leading-hidden (rather than hidden-leading)

```html
<div class="mdc-chip mdc-chip--selected">
<i class="material-icons mdc-chip__icon mdc-chip__icon--leading mdc-chip__icon--hidden-leading">face</i>
<div class="mdc-chip__checkmark" >
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: Remove space before >

*/
manageSelection(chip) {
select(chipFoundation) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This refactored code is beautiful. Nice work!! 😀

@bonniezhou bonniezhou merged commit 66f2464 into master Apr 6, 2018
@bonniezhou bonniezhou deleted the fix/chips/selected branch April 9, 2018 17:58
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