Skip to content

Commit

Permalink
Merge pull request #6 in FFE/ffe-searchable-dropdown-react from maste…
Browse files Browse the repository at this point in the history
…r_enable-update-of-dropdown-list to master

* commit '0efef17e8fe22eaec046c0a6136aecec6be574b9':
  Set atribute inputValue to enable reset and update from outside the component
  • Loading branch information
Anlaug Underdal committed Aug 23, 2017
2 parents 814fc59 + dab5d5e commit a50e794
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 88 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog for ffe-search-dropdown-react

## v.2.0.0
* Set inputValue outside the component to be able to reset and
change the value without interfering with the component.
* attributes onSelect, onReset and onChange should now update inputValue and not return it.
* Removed attribute initialInputValue, added attribute inputValue.

## v1.1.4
* hotfix div wrapper classname with version for npm

Expand Down
18 changes: 2 additions & 16 deletions mock/mockCustomExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,6 @@ exports.companies = [
}
];

exports.initialInputValue = exports.companies[0].organizationName;
let selectedCompanyName = exports.companies[0].organizationName;

exports.onSelect = function (company) {
selectedCompanyName = company.organizationName;
return selectedCompanyName;
};

exports.onReset = function () {
return selectedCompanyName;
};

exports.onChange = function (value) {
return value;
};

exports.renderItem = unreadLabel => company => (
<div style={{cursor:"pointer"}}>
<a className="ffe-searchable-dropdown__item--header">{company.organizationName}</a>
Expand All @@ -62,3 +46,5 @@ exports.renderItem = unreadLabel => company => (
</div>
);



15 changes: 0 additions & 15 deletions mock/mockDefaultExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,3 @@ const exports = module.exports = {};

exports.companies = [{companyName: "Bedrift 1"}, {companyName:"Bedrift 2"}];

exports.initialInputValue = exports.companies[0].companyName;
let selectedCompanyName = exports.companies[0].companyName;

exports.onSelect = function (company) {
selectedCompanyName = company.companyName;
return selectedCompanyName;
};

exports.onReset = function () {
return '';
};

exports.onChange = function (value) {
return value;
};
16 changes: 0 additions & 16 deletions mock/mockTwoValueListElementExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,3 @@ exports.companies = [
}
];

exports.initialInputValue ='';
let selectedCompanyName = exports.companies[0].organizationName;

exports.onSelect = function (company) {
selectedCompanyName = company.organizationName;
return selectedCompanyName;
};

exports.onReset = function () {
return '';
};

exports.onChange = function (value) {
return value;
};

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ffe-searchable-dropdown-react",
"version": "1.1.4",
"version": "2.0.0",
"description": "Dropdown with search option",
"scripts": {
"build": "babel -d lib --ignore=*.test.js src",
Expand Down
9 changes: 4 additions & 5 deletions src/InputField.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/*eslint-env jest */
import { shallow } from 'enzyme';
import React from 'react';
import defaultMock from '../mock/mockDefaultExample';
import Input from './InputField';
const i = t => t;

Expand All @@ -14,7 +13,7 @@ describe('<Input>', () => {
onFocus: i,
onKeyDown: i,
placeholder:"Velg",
onInputChange:defaultMock.onChange,
onInputChange:i,
displayResetWhenInputHasValue:true,
inputId: 'anId',
inputValue:'',
Expand All @@ -27,16 +26,16 @@ describe('<Input>', () => {
test('renders', () =>
expect(component.find('.ffe-searchable-dropdown__dropdown-input-field')).toHaveLength(1));

test('input field has an Id', () =>
expect(component.find('input').prop('id')).toBe('anId'));
test('input field has an Id', () =>
expect(component.find('input').prop('id')).toBe('anId'));

test('input field is empty', () => {
expect(component.find('input').prop('value')).toBe('');
});

test('displays reset when input has value', () => {
const componentWithInputValue = mountInputFieldWithProps({...props, inputValue:'aa'});
expect(componentWithInputValue.find('input').prop('value')).toBe('aa');
expect(componentWithInputValue.find('input').prop('value')).toBe('aa');
expect(componentWithInputValue.find('.ffe-searchable-dropdown__reset-button')).toHaveLength(1);
});

Expand Down
35 changes: 14 additions & 21 deletions src/SearchableDropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ class SearchableDropdown extends Component {
constructor(props) {
super(props);
this.state = {
filteredList: this.props.dropdownList,
highlightedElementIndex: -1,
searchTerm: '',
showListContainer: false,
value:this.props.initialInputValue ? this.props.initialInputValue : '',
};

this.filterList = this.filterList.bind(this);
Expand All @@ -40,20 +38,18 @@ class SearchableDropdown extends Component {
onReset() {
this.setState ({
searchTerm: '',
value: this.props.onReset(),
filteredList: this.props.dropdownList,
});
this.props.onReset();
}

onInputChange(event) {
const searchTerm = event.target.value;
this.setState({
showListContainer:true,
searchTerm: searchTerm,
value: this.props.onInputChange(searchTerm),
highlightedElementIndex: -1,
});
this.filterList(searchTerm);
this.props.onInputChange(searchTerm);
}

filterList(searchTerm) {
Expand All @@ -69,23 +65,21 @@ class SearchableDropdown extends Component {
} else {
updatedList = this.props.dropdownList;
}
this.setState({
filteredList: updatedList,
});
return updatedList;
}

onSelect(value) {
this.setState({
showListContainer:false,
searchTerm: '',
value: this.props.onSelect(value),
highlightedElementIndex: -1,
filteredList: this.props.dropdownList,
});
this.props.onSelect(value);
}

onKeyDown(event) {
const { highlightedElementIndex, filteredList } = this.state;
const { highlightedElementIndex, searchTerm } = this.state;
const filteredList = this.filterList(searchTerm);
if (event.key === 'ArrowDown') {
this.setState({showListContainer:true});
this.setHighlightedIndex("DOWN", highlightedElementIndex, filteredList);
Expand Down Expand Up @@ -130,7 +124,6 @@ class SearchableDropdown extends Component {
filteredListLength -1 : highlightedElementIndex -1;
this.setState({highlightedElementIndex: nextHighlightedIndex });


if (nextHighlightedIndex === filteredListLength - 1) {
if (this.state.showListContainer === true) {
this.scrollContainer.setScrollPosEnd();
Expand All @@ -144,7 +137,8 @@ class SearchableDropdown extends Component {

render() {
const { dropdownAttributes, noMatch, placeholder, renderDropdownElement, label } = this.props;
const { filteredList, highlightedElementIndex, showListContainer } = this.state;
const { highlightedElementIndex, showListContainer, searchTerm } = this.state;
const filteredList = this.filterList(searchTerm);
return (
<div className={ classNames(this.props.className) }>
{label?
Expand All @@ -168,7 +162,7 @@ class SearchableDropdown extends Component {
onKeyDown={this.onKeyDown}
placeholder={placeholder}
inputId={this.props.inputId}
inputValue={this.state.value}
inputValue={this.props.inputValue}
onReset={this.onReset}
searchTerm={this.state.searchTerm}
ariaInvalid={this.props.ariaInvalid}
Expand All @@ -188,12 +182,10 @@ class SearchableDropdown extends Component {
}
</div>
</div>

);
}
}


SearchableDropdown.propTypes = {
/** Display reset when input has value */
displayResetWhenInputHasValue: bool,
Expand All @@ -207,15 +199,17 @@ SearchableDropdown.propTypes = {
label: string,
/** Id attribute on the input element */
inputId: isRequiredIf(string, props => props.label),
/** Value of input field */
inputValue: string,
/** value to be displayed in dropdown in case of search with no match */
noMatch: string.isRequired,
/** Function receives value of inputField and should return with value of inputField */
/** Function receives value of inputField and should update inputValue */
onInputChange: func.isRequired,
/** Function receives no input expects no return */
onBlur: func,
/** Function receives selected object, should return value to be displayed in input field */
/** Function receives selected object, should update inputValue */
onSelect: func.isRequired,
/** Function gets no input, should return value to be displayed in input field */
/** Function gets no input, should update inputValue */
onReset: func.isRequired,
/** Placeholder for input field when empty */
placeholder: string,
Expand All @@ -229,7 +223,6 @@ SearchableDropdown.propTypes = {
className: string,
};


SearchableDropdown.defaultProps = {
displayResetWhenInputHasValue: false,
ariaInvalid: false,
Expand Down
28 changes: 17 additions & 11 deletions src/SearchableDropdown.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
The default:

```example
initialState = { inputValue: '' };
<SearchableDropdown
dropdownList={mockDefaultExample.companies}
placeholder="Velg"
noMatch="Søket ga ingen treff"
dropdownAttributes={['companyName']}
searchAttributes={['companyName']}
onSelect={mockDefaultExample.onSelect}
onInputChange={mockDefaultExample.onChange}
onReset={mockDefaultExample.onReset}
onSelect={(company) => setState({ inputValue: company.companyName })}
onInputChange={(value) => setState({ inputValue: value })}
onReset={() => setState({ inputvalue: '' })}
displayResetWhenInputHasValue = {true}
inputValue={state.inputValue}
inputId = "default"
/>
```

With listElements of two values

```example
initialState = { inputValue: '' };
<SearchableDropdown
dropdownList={ mockTwoValueListElementExample.companies }
placeholder="Velg"
noMatch="Søket ga ingen treff"
dropdownAttributes={['organizationName', 'organizationNumber']}
searchAttributes={['organizationName', 'organizationNumber']}
onSelect={mockTwoValueListElementExample.onSelect}
onInputChange={mockTwoValueListElementExample.onChange}
onReset={mockTwoValueListElementExample.onReset}
onSelect={(company) => setState({inputValue: company.organizationName})}
onInputChange={(value) => setState({inputValue: value})}
onReset={() => setState({inputValue: ''})}
displayResetWhenInputHasValue = {true}
inputValue={state.inputValue}
label = "Fund"
inputId = "two values"
/>
Expand All @@ -36,15 +40,17 @@ With listElements of two values
with custom list element missing inputId for inputField

```example
initialState = { inputValue: mockCustomExample.companies[0].organizationName,
selectedCompanyName: mockCustomExample.companies[0].organizationName};
<SearchableDropdown
dropdownList={ mockCustomExample.companies }
noMatch="Søket ga ingen treff"
searchAttributes={['organizationName', 'organizationNumber']}
renderDropdownElement={mockCustomExample.renderItem("ulest")}
initialInputValue={mockCustomExample.initialInputValue}
onSelect={mockCustomExample.onSelect}
onInputChange={mockCustomExample.onChange}
onReset={mockCustomExample.onReset}
label = "Fund"
inputValue={state.inputValue}
onSelect={(company) => setState({inputValue: company.organizationName, selectedCompanyName:company.organizationName})}
onInputChange={(value) => setState({inputValue: value})}
onReset={() => setState({inputValue: state.selectedCompanyName})}
label = "Fund"
/>
```
7 changes: 4 additions & 3 deletions src/SearchableDropdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ describe('<SearchableDropdown>', () => {
noMatch:"Søket ga ingen treff",
dropdownAttributes:['companyName'],
searchAttributes:['companyName'],
onSelect:defaultMock.onSelect,
onInputChange:defaultMock.onChange,
onReset:defaultMock.onReset,
onSelect:i,
onInputChange:i,
onReset:i,
inputValue:'',
displayResetWhenInputHasValue:true,
label:"Foo",
inputId: "inputid"
Expand Down

0 comments on commit a50e794

Please sign in to comment.