Skip to content

Commit a9ed216

Browse files
committed
search
1 parent 3eb0827 commit a9ed216

File tree

2 files changed

+81
-37
lines changed

2 files changed

+81
-37
lines changed

src/controls/sitePicker/ISitePicker.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,23 @@ export interface ISitePickerProps {
7272
isDesc?: boolean;
7373

7474
/**
75-
* selection change handler
75+
* Selection change handler
7676
*/
7777
onChange: (selectedSites: ISite[]) => void;
78+
79+
/**
80+
* Input placeholder text. Displayed until option is selected.
81+
*/
82+
placeholder?: string;
83+
84+
/**
85+
* Search input placeholder text. Displayed until search text is entered.
86+
*/
87+
searchPlaceholder?: string;
88+
89+
/**
90+
* The list will be filtered after users stop typing for `deferredSearchTime` milliseconds.
91+
* Default value is 200.
92+
*/
93+
deferredSearchTime?: number;
7894
}

src/controls/sitePicker/SitePicker.tsx

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import orderBy from 'lodash/orderBy';
99
import findIndex from 'lodash/findIndex';
1010
import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox';
1111
import { toRelativeUrl } from '../../common/utilities/GeneralHelper';
12+
import { Async } from '@uifabric/utilities/lib/Async';
1213

1314
const styles = mergeStyleSets({
1415
loadingSpinnerContainer: {
@@ -44,6 +45,8 @@ const styles = mergeStyleSets({
4445
}
4546
});
4647

48+
const async = new Async();
49+
4750
export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: React.PropsWithChildren<ISitePickerProps>) => {
4851

4952
const {
@@ -57,7 +60,10 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
5760
allowSearch,
5861
orderBy: propOrderBy,
5962
isDesc,
60-
onChange
63+
onChange,
64+
placeholder,
65+
searchPlaceholder,
66+
deferredSearchTime
6167
} = props;
6268

6369
const [isLoading, setIsLoading] = React.useState<boolean>(true);
@@ -66,24 +72,45 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
6672
const [filteredSites, setFilteredSites] = React.useState<ISite[]>();
6773
const [searchQuery, setSearchQuery] = React.useState<string>();
6874

69-
const onRenderOption = (option?: ISelectableOption, defaultRender?: (props?: ISelectableOption) => JSX.Element | null): JSX.Element | null => {
70-
if (!props) {
71-
return null;
75+
const onSearchChange = React.useCallback((newSearchQuery: string) => {
76+
if (!allSites) {
77+
return;
7278
}
7379

74-
if (option.itemType === SelectableOptionMenuItemType.Header) {
75-
return <SearchBox />;
80+
const loweredNewSearchQuery = newSearchQuery.toLowerCase();
81+
const newFilteredSites = allSites.filter(s => s.title && s.title.toLowerCase().indexOf(loweredNewSearchQuery) !== -1);
82+
83+
setSearchQuery(newSearchQuery);
84+
// hack to make dropdown update
85+
setFilteredSites([]);
86+
setFilteredSites(newFilteredSites);
87+
}, [allSites]);
88+
89+
const onSelectionChange = React.useCallback((e, item: IDropdownOption, index: number) => {
90+
const newSelectedSites = selectedSites ? [...selectedSites] : [];
91+
92+
if (multiSelect !== false) {
93+
const existingIndex = findIndex(newSelectedSites, s => s.id === item.key);
94+
95+
if (existingIndex >= 0) {
96+
newSelectedSites.splice(existingIndex, 1);
97+
}
98+
else {
99+
newSelectedSites.push({
100+
...item.data!
101+
});
102+
}
103+
}
104+
105+
if (onChange) {
106+
onChange(newSelectedSites);
76107
}
77-
// {multiSelect !== false && <Checkbox className={styles.siteOptionCheckbox} checked={option.selected} disabled={option.disabled} />}
78-
return <div className={styles.siteOption}>
79-
<div className={styles.siteOptionContent}>
80-
<span className={styles.siteOptionTitle}>{option.text}</span>
81-
<span className={styles.siteOptionUrl}>{toRelativeUrl(option.data!.url)}</span>
82-
</div>
83-
</div>;
84-
};
85108

86-
const getOptions = (): IDropdownOption[] => {
109+
setSelectedSites(newSelectedSites);
110+
111+
}, [selectedSites, multiSelect, onChange]);
112+
113+
const getOptions = React.useCallback((): IDropdownOption[] => {
87114
const result: IDropdownOption[] = [];
88115

89116
if (allowSearch) {
@@ -107,32 +134,29 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
107134
});
108135
}
109136

137+
console.log(result);
110138
return result;
111-
};
139+
}, [allowSearch, selectedSites, filteredSites]);
112140

113-
const onSelectionChange = React.useCallback((e, item: IDropdownOption, index: number) => {
114-
const newSelectedSites = selectedSites ? [...selectedSites] : [];
115-
116-
if (multiSelect !== false) {
117-
const existingIndex = findIndex(newSelectedSites, s => s.id === item.key);
118-
119-
if (existingIndex >= 0) {
120-
newSelectedSites.splice(existingIndex, 1);
121-
}
122-
else {
123-
newSelectedSites.push({
124-
...item.data!
125-
});
126-
}
141+
const onRenderOption = (option?: ISelectableOption, defaultRender?: (props?: ISelectableOption) => JSX.Element | null): JSX.Element | null => {
142+
if (!props) {
143+
return null;
127144
}
128145

129-
if (onChange) {
130-
onChange(newSelectedSites);
146+
if (option.itemType === SelectableOptionMenuItemType.Header) {
147+
return <SearchBox
148+
placeholder={searchPlaceholder}
149+
value={searchQuery}
150+
onChange={async.debounce(onSearchChange, deferredSearchTime || 200)} />;
131151
}
132-
133-
setSelectedSites(newSelectedSites);
134-
135-
}, [selectedSites, multiSelect, onChange]);
152+
// {multiSelect !== false && <Checkbox className={styles.siteOptionCheckbox} checked={option.selected} disabled={option.disabled} />}
153+
return <div className={styles.siteOption}>
154+
<div className={styles.siteOptionContent}>
155+
<span className={styles.siteOptionTitle}>{option.text}</span>
156+
<span className={styles.siteOptionUrl}>{toRelativeUrl(option.data!.url)}</span>
157+
</div>
158+
</div>;
159+
};
136160

137161
React.useEffect(() => {
138162
if (!initialSites) {
@@ -200,11 +224,15 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
200224
<>
201225
<Dropdown
202226
label={label}
227+
placeholder={placeholder}
203228
options={getOptions()}
229+
selectedKey={multiSelect === false && !!selectedSites && !!selectedSites[0] ? selectedSites[0].id : undefined}
230+
selectedKeys = { multiSelect !== false && !!selectedSites ? selectedSites.map(s => s.id) : undefined }
204231
disabled={disabled}
205232
multiSelect={multiSelect !== false}
206233
onRenderOption={onRenderOption}
207234
onChange={onSelectionChange}
235+
notifyOnReselect={true}
208236
/>
209237
</>
210238
);

0 commit comments

Comments
 (0)