Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "office-ui-fabric-react",
"comment": "Add async debounce option to BasePicker",
"type": "minor"
}
],
"packageName": "office-ui-fabric-react",
"email": "jabrassi@microsoft.com"
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<

public componentDidMount() {
this.selection.setItems(this.state.items);
this._onResolveSuggestions = this._async.debounce(this._onResolveSuggestions, this.props.resolveDelay);
}

public componentWillReceiveProps(newProps: P) {
Expand Down Expand Up @@ -313,8 +314,7 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<
}

protected updateValue(updatedValue: string) {
const suggestions: T[] | PromiseLike<T[]> = this.props.onResolveSuggestions(updatedValue, this.state.items);
this.updateSuggestionsList(suggestions, updatedValue);
this._onResolveSuggestions(updatedValue);
}

protected updateSuggestionsList(suggestions: T[] | PromiseLike<T[]>, updatedValue?: string) {
Expand Down Expand Up @@ -683,6 +683,14 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent<
this.onChange(items);
}

private _onResolveSuggestions(updatedValue: string): void {
const suggestions: T[] | PromiseLike<T[]> | null = this.props.onResolveSuggestions(updatedValue, this.state.items);

if (suggestions !== null) {
this.updateSuggestionsList(suggestions, updatedValue);
}
}

private _onValidateInput() {
if (this.props.onValidateInput && (this.props.onValidateInput as any)(this.input.value) !== ValidationState.invalid && this.props.createGenericItem) {
const itemToConvert = this.props.createGenericItem(this.input.value, this.props.onValidateInput(this.input.value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,15 @@ export interface IBasePickerProps<T> extends React.Props<any> {
/**
* A callback for what should happen when a person types text into the input.
* Returns the already selected items so the resolver can filter them out.
* If used in conjunction with resolveDelay this will ony kick off after the delay throttle.
*/
onResolveSuggestions: (filter: string, selectedItems?: T[]) => T[] | PromiseLike<T[]>;
/**
* The delay time in ms before resolving suggestions, which is kicked off when input has been cahnged.
* e.g. If a second input change happens within the resolveDelay time, the timer will start over.
* Only until after the timer completes will onResolveSuggestions be called.
*/
resolveDelay?: number;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a default? Should it default to something? Will it get treated as no delay without it?

Copy link
Copy Markdown
Contributor Author

@machineloop machineloop Mar 3, 2018

Choose a reason for hiding this comment

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

Good question, right now no default is set so that if the resolveDelay prop isn't passed in, there's no delay but still passes through debounced function.

I felt an opt-in was safer than setting default, but if you feel this should be a default behavior, we can add one. The delay I'm using in the examples is 300 ms

/**
* A callback for what should happen when a user clicks the input.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
'aria-label': 'People Picker'
} }
componentRef={ this._resolveRef('_picker') }
resolveDelay={ 300 }
/>
);
}
Expand All @@ -174,6 +175,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
} }
componentRef={ this._resolveRef('_picker') }
onInputChange={ this._onInputChange }
resolveDelay={ 300 }
/>
);
}
Expand All @@ -194,6 +196,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
'aria-label': 'People Picker'
} }
componentRef={ this._resolveRef('_picker') }
resolveDelay={ 300 }
/>
);
}
Expand All @@ -216,6 +219,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
'aria-label': 'People Picker'
} }
componentRef={ this._resolveRef('_picker') }
resolveDelay={ 300 }
/>
);
}
Expand All @@ -238,6 +242,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
'aria-label': 'People Picker'
} }
componentRef={ this._resolveRef('_picker') }
resolveDelay={ 300 }
/>
);
}
Expand All @@ -260,6 +265,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
'aria-label': 'People Picker'
} }
componentRef={ this._resolveRef('_picker') }
resolveDelay={ 300 }
/>
);
}
Expand Down Expand Up @@ -287,6 +293,7 @@ export class PeoplePickerTypesExample extends BaseComponent<any, IPeoplePickerEx
onFocus: (ev: React.FocusEvent<HTMLInputElement>) => console.log('onFocus called')
} }
componentRef={ this._resolveRef('_picker') }
resolveDelay={ 300 }
/>
<label> Click to Add a person </label>
{ controlledItems.map((item, index) => <div key={ index }>
Expand Down