Skip to content
This repository has been archived by the owner on Jan 15, 2021. It is now read-only.

Commit

Permalink
feat(option support): Support objects
Browse files Browse the repository at this point in the history
Use labelKey and valueKey to use objects as data source

closes #3
  • Loading branch information
Aidurber committed Dec 26, 2017
1 parent 44fa058 commit 0535d79
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 29 deletions.
87 changes: 64 additions & 23 deletions src/Picky.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ class Picky extends React.Component {
this.toggleDropDown = this.toggleDropDown.bind(this);
this.selectAll = this.selectAll.bind(this);
this.onFilterChange = this.onFilterChange.bind(this);
this.isDataObject = this.isDataObject.bind(this);
}

componentDidMount() {}
selectValue(value) {
if (this.props.multiple && Array.isArray(this.props.value)) {
if (this.props.value.includes(value)) {
Expand Down Expand Up @@ -58,6 +58,7 @@ class Picky extends React.Component {
}
}
allSelected() {
if (!this.props.multiple) return false;
return (
this.props.options
.map(opt => opt)
Expand All @@ -80,8 +81,23 @@ class Picky extends React.Component {
}
);
}
isDataObject(obj) {
const { valueKey, labelKey } = this.props;
return (
typeof obj === 'object' &&
obj.hasOwnProperty(valueKey) &&
obj.hasOwnProperty(labelKey)
);
}
renderOptions() {
const { options, value, dropdownHeight } = this.props;
const {
options,
value,
dropdownHeight,
valueKey,
labelKey,
multiple
} = this.props;
const items = this.state.filtered ? this.state.filteredOptions : options;
return (
<VirtualList
Expand All @@ -91,22 +107,31 @@ class Picky extends React.Component {
itemSize={35}
renderItem={({ index, style }) => {
let isSelected = false;
const option = items[index];
if (
(Array.isArray(value) && value.includes(option)) ||
(!Array.isArray(value) && value === option)
) {
const current = items[index];
if (Array.isArray(value) && value.includes(current)) {
isSelected = true;
} else if (!Array.isArray(value) && value === current) {
isSelected = true;
} else if (Array.isArray(value) && value.includes(current)) {
return true;
}
let body = '';
if (this.isDataObject(current)) {
body = current[labelKey];
} else {
body = current;
}
return (
<li
key={option}
key={this.isDataObject(current) ? current[valueKey] : current}
style={style}
className={isSelected ? 'selected' : ''}
onClick={() => this.selectValue(option)}
onClick={() => this.selectValue(current)}
>
<input type="checkbox" checked={isSelected} readOnly />
{option}
{multiple && (
<input type="checkbox" checked={isSelected} readOnly />
)}
{body}
</li>
);
}}
Expand All @@ -120,9 +145,16 @@ class Picky extends React.Component {
filteredOptions: []
});
}
const filteredOptions = this.props.options.filter(option =>
String(option).includes(value)
);
const filteredOptions = this.props.options.filter(option => {
if (this.isDataObject(option)) {
return String(option[this.props.labelKey])
.toLowerCase()
.includes(value.toLowerCase());
}
return String(option)
.toLowerCase()
.includes(value.toLowerCase());
});
this.setState(
{
filtered: true,
Expand Down Expand Up @@ -158,7 +190,9 @@ class Picky extends React.Component {
numberDisplayed,
includeSelectAll,
includeFilter,
filterDebounce
filterDebounce,
valueKey,
labelKey
} = this.props;
const { open } = this.state;
return (
Expand All @@ -173,6 +207,8 @@ class Picky extends React.Component {
value={value}
multiple={multiple}
numberDisplayed={numberDisplayed}
valueKey={valueKey}
labelKey={labelKey}
/>
</button>
{open && (
Expand All @@ -194,11 +230,13 @@ class Picky extends React.Component {
className={this.allSelected() ? 'selected' : ''}
onClick={this.selectAll}
>
<input
type="checkbox"
checked={this.allSelected()}
readOnly
/>{' '}
{multiple && (
<input
type="checkbox"
checked={this.allSelected()}
readOnly
/>
)}
Select All
</li>
)}
Expand All @@ -223,8 +261,9 @@ Picky.propTypes = {
value: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string,
PropTypes.number
]).isRequired,
PropTypes.number,
PropTypes.object
]),
numberDisplayed: PropTypes.number,
multiple: PropTypes.bool,
options: PropTypes.array.isRequired,
Expand All @@ -236,7 +275,9 @@ Picky.propTypes = {
dropdownHeight: PropTypes.number,
onFiltered: PropTypes.func,
onOpen: PropTypes.func,
onClose: PropTypes.func
onClose: PropTypes.func,
valueKey: PropTypes.string,
labelKey: PropTypes.string
};

export default Picky;
54 changes: 48 additions & 6 deletions src/Placeholder.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,64 @@
// NEEDS REFACTOR
import React from 'react';
import PropTypes from 'prop-types';
const Placeholder = ({ placeholder, value, numberDisplayed, multiple }) => {
const Placeholder = ({
placeholder,
value,
numberDisplayed,
multiple,
valueKey,
labelKey
}) => {
let message = '';
// Show placeholder if no value
if (!value || !value.length) {

if (
value === null ||
value === undefined ||
(Array.isArray(value) && !value.length)
) {
message = placeholder;
} else if (Array.isArray(value)) {
// If type is array and values length less than number displayed
// join the values
if (multiple) {
if (value.length <= numberDisplayed) {
message = value.join(', ');
message = value
.map(opt => {
if (
typeof opt === 'object' &&
opt.hasOwnProperty(valueKey) &&
opt.hasOwnProperty(labelKey)
) {
return opt[labelKey];
}
return opt;
})
.join(', ');
} else {
//If more than numberDisplayed then show "length selected"
message = `${value.length} selected`;
}
} else {
if (
typeof value === 'object' &&
value.hasOwnProperty(valueKey) &&
value.hasOwnProperty(labelKey)
) {
message = value[labelKey];
}
message = value[0].toString();
}
} else {
message = value;
if (
typeof value === 'object' &&
value.hasOwnProperty(valueKey) &&
value.hasOwnProperty(labelKey)
) {
message = value[labelKey];
} else {
message = value;
}
}
return <span className="picky__placeholder">{message}</span>;
};
Expand All @@ -32,10 +71,13 @@ Placeholder.propTypes = {
value: PropTypes.oneOfType([
PropTypes.array,
PropTypes.string,
PropTypes.number
PropTypes.number,
PropTypes.object
]),
numberDisplayed: PropTypes.number,
multiple: PropTypes.bool
multiple: PropTypes.bool,
valueKey: PropTypes.string,
labelKey: PropTypes.string
};

export default Placeholder;
24 changes: 24 additions & 0 deletions tests/Picky.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,30 @@ describe('Picky', () => {
expect(onChange).lastCalledWith([]);
expect(wrapper.state('selectedValue')).toEqual([]);
});

it('should support object options single select', () => {
const options = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' }
];
const wrapper = mount(
<Picky
value={null}
options={options}
open={true}
valueKey="id"
labelKey="name"
/>
);

wrapper
.find('.picky__dropdown li')
.at(0)
.simulate('click');

expect(wrapper.state('selectedValue')).toEqual({ id: 1, name: 'Item 1' });
});
});

describe('Filter', () => {
Expand Down

0 comments on commit 0535d79

Please sign in to comment.