Skip to content
This repository was archived by the owner on Jul 29, 2025. It is now read-only.

Commit 8435079

Browse files
author
Matt Goo
authored
fix(chips): remove handleRemove method for chipsUpdate method (#282)
1 parent ba433ea commit 8435079

File tree

4 files changed

+79
-36
lines changed

4 files changed

+79
-36
lines changed

packages/chips/ChipSet.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,14 +97,33 @@ export default class ChipSet extends Component {
9797
}
9898

9999
handleRemove = (chipId) => {
100-
const {input, handleRemove} = this.props;
100+
const {input} = this.props;
101101
if (input) {
102102
// this should be calling foundation_.handleChipRemoval, but we would
103103
// need to pass evt.detail.chipId
104104
// fix when MDC Web issue 3613 is fixed
105105
this.foundation_.deselect(chipId);
106106
}
107-
handleRemove(chipId);
107+
this.removeChip(chipId);
108+
}
109+
110+
// this should be adapter_.removeChip, but cannot be complete until
111+
// https://github.com/material-components/material-components-web/issues/3613
112+
// is fixed
113+
removeChip = (chipId) => {
114+
const {updateChips, children} = this.props;
115+
if (!children) return;
116+
117+
const chips = React.Children.toArray(children).slice();
118+
for (let i = 0; i < chips.length; i ++) {
119+
const chip = chips[i];
120+
if (chip.props.id === chipId) {
121+
chips.splice(i, 1);
122+
break;
123+
}
124+
}
125+
const chipsArray = chips.length ? chips.map((chip) => chip.props) : [];
126+
updateChips(chipsArray);
108127
}
109128

110129
setCheckmarkWidth = (checkmark) => {
@@ -148,7 +167,7 @@ ChipSet.propTypes = {
148167
className: PropTypes.string,
149168
selectedChipIds: PropTypes.array,
150169
handleSelect: PropTypes.func,
151-
handleRemove: PropTypes.func,
170+
updateChips: PropTypes.func,
152171
choice: PropTypes.bool,
153172
filter: PropTypes.bool,
154173
input: PropTypes.bool,
@@ -159,7 +178,7 @@ ChipSet.defaultProps = {
159178
className: '',
160179
selectedChipIds: [],
161180
handleSelect: () => {},
162-
handleRemove: () => {},
181+
updateChips: () => {},
163182
choice: false,
164183
filter: false,
165184
input: false,

packages/chips/README.md

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class MyFilterChips extends React.Component {
9898

9999
### Input chips
100100

101-
Input chips are a variant of chips which enable user input by converting text into chips. Chips may be dynamically added and removed from the chip set. To define a set of chips as input chips, add the `input` prop to the `ChipSet`. To remove a chip, pass a callback to the `Chip` through the `handleRemove` prop.
101+
Input chips are a variant of chips which enable user input by converting text into chips. Chips may be dynamically added and removed from the chip set. To define a set of chips as input chips, add the `input` prop to the `ChipSet`. When a chip is removed, the component will notify you through the `updateChips` prop callback. `updateChips` will pass an array of props representing the specified chip data. The example below shows you how to use this.
102102

103103
> _NOTE_: We recommend you store an array of chip labels and their respective IDs in the `state` to manage adding/removing chips. Do _NOT_ use the chip's index as its ID or key, because its index may change due to the addition/removal of other chips.
104104
@@ -118,26 +118,21 @@ class MyInputChips extends React.Component {
118118
const id = label.replace(/\s/g,'');
119119
// Create a new chips array to ensure that a re-render occurs.
120120
// See: https://reactjs.org/docs/state-and-lifecycle.html#do-not-modify-state-directly
121-
const chips = [...this.state.chips];
121+
const chips = [...this.state.chips];
122122
chips.push({label, id});
123123
this.setState({chips});
124124
e.target.value = '';
125125
}
126126
}
127127

128-
// Removes the chip element from the page
129-
handleRemove = (id) => {
130-
const chips = [...this.state.chips];
131-
const index = chips.findIndex(chip => chip.id === id);
132-
chips.splice(index, 1);
133-
this.setState({chips});
134-
}
135-
136128
render() {
137129
return (
138130
<div>
139131
<input type="text" onKeyDown={this.handleKeyDown} />
140-
<ChipSet input handleRemove={this.handleRemove}>
132+
<ChipSet
133+
input
134+
updateChips={(chips) => this.setState({chips})}
135+
>
141136
{this.state.chips.map((chip) =>
142137
<Chip
143138
key={chip.id} // The chip's key cannot be its index, because its index may change.
@@ -161,7 +156,7 @@ Prop Name | Type | Description
161156
className | String | Classes to be applied to the chip set element
162157
selectedChipIds | Array | Array of ids of chips that are selected
163158
handleSelect | Function(id: string) => void | Callback for selecting the chip with the given id
164-
handleRemove | Function(id: string) => void | Callback for removing the chip with the given id
159+
updateChips | Function(chips: Array{chipProps}) => void | Callback when the ChipSet updates its chips
165160
choice | Boolean | Indicates that the chips in the set are choice chips, which allow single selection from a set of options
166161
filter | Boolean | Indicates that the chips in the set are filter chips, which allow multiple selection from a set of options
167162
input | Boolean | Indicates that the chips in the set are input chips, where chips can be added or removed

test/screenshot/chips/index.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -82,17 +82,8 @@ class InputChipsTest extends React.Component {
8282
/>
8383
<ChipSet
8484
input
85-
// handleRemove removes the chip element from the page
86-
handleRemove={(chipId) => {
87-
const {chips} = this.state;
88-
for (let i = 0; i < chips.length; i ++) {
89-
if (chips[i].id === chipId) {
90-
chips.splice(index, 1);
91-
this.setState(chips);
92-
return;
93-
}
94-
}
95-
}}>
85+
updateChips={(chips) => this.setState({chips})}
86+
>
9687
{this.state.chips.map((chip) =>
9788
<Chip
9889
id={chip.id}

test/unit/chips/ChipSet.test.js

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,7 @@ test('#handleSelect does not call foundation_.toggleSelect with chipId if is nei
145145
});
146146

147147
test('#handleRemove calls foundation_.deselect with chipId and is input variant', () => {
148-
const handleRemove = td.func();
149-
const wrapper = shallow(<ChipSet input handleRemove={handleRemove}>
148+
const wrapper = shallow(<ChipSet input>
150149
<div id='1' />
151150
</ChipSet>);
152151
wrapper.instance().foundation_.deselect = td.func();
@@ -164,11 +163,48 @@ test('#handleRemove does not call foundation_.deselect with chipId if is not inp
164163
td.verify(wrapper.instance().foundation_.deselect('1'), {times: 0});
165164
});
166165

167-
test('#handleRemove calls props.handleRemove with chipId', () => {
168-
const handleRemove = td.func();
169-
const wrapper = shallow(<ChipSet handleRemove={handleRemove}></ChipSet>);
166+
test('#handleRemove calls removeChip', () => {
167+
const wrapper = shallow(<ChipSet>
168+
<div id='1' />
169+
</ChipSet>);
170+
wrapper.instance().removeChip = td.func();
170171
wrapper.instance().handleRemove('1');
171-
td.verify(handleRemove('1'), {times: 1});
172+
td.verify(wrapper.instance().removeChip('1'), {times: 1});
173+
});
174+
175+
test('#removeChip does not call #props.updateChips if there are no chips', () => {
176+
const updateChips = td.func();
177+
const wrapper = shallow(<ChipSet updateChips={updateChips}/>);
178+
wrapper.instance().removeChip();
179+
td.verify(updateChips(td.matchers.anything()), {times: 0});
180+
});
181+
182+
test('#removeChip calls #props.updateChips with array of remove chip', () => {
183+
const updateChips = td.func();
184+
const wrapper = shallow(<ChipSet updateChips={updateChips}>
185+
<div id='1' />
186+
</ChipSet>);
187+
wrapper.instance().removeChip('1');
188+
td.verify(updateChips([]), {times: 1});
189+
});
190+
191+
test('#removeChip calls #props.updateChips with array of removed chip', () => {
192+
const updateChips = td.func();
193+
const wrapper = shallow(<ChipSet updateChips={updateChips}>
194+
<div id='1' />
195+
</ChipSet>);
196+
wrapper.instance().removeChip('1');
197+
td.verify(updateChips([]), {times: 1});
198+
});
199+
200+
test('#removeChip calls #props.updateChips with array of remaining chips', () => {
201+
const updateChips = td.func();
202+
const wrapper = shallow(<ChipSet updateChips={updateChips}>
203+
<div id='1' />
204+
<div id='2' />
205+
</ChipSet>);
206+
wrapper.instance().removeChip('1');
207+
td.verify(updateChips([{id: '2'}]), {times: 1});
172208
});
173209

174210
test('#setCheckmarkWidth sets checkmark width', () => {
@@ -231,11 +267,13 @@ test('chip is rendered with handleSelect method', () => {
231267
});
232268

233269
test('chip is rendered with handleRemove method', () => {
234-
const handleRemove = td.func();
235-
const wrapper = mount(<ChipSet handleRemove={handleRemove}><Chip id='1'/></ChipSet>);
270+
const wrapper = mount(<ChipSet></ChipSet>);
271+
wrapper.instance().handleRemove = td.func();
272+
wrapper.setProps({children: <Chip id='1'/>});
273+
236274
const chip = wrapper.children().props().children[0];
237275
chip.props.handleRemove('1');
238-
td.verify(handleRemove('1'), {times: 1});
276+
td.verify(wrapper.instance().handleRemove('1'), {times: 1});
239277
});
240278

241279
test('chip is rendered ChipCheckmark if is filter variants', () => {

0 commit comments

Comments
 (0)