-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implemented BasePicker itemLimit #2553
Conversation
@ohritz, |
@@ -93,6 +93,11 @@ export interface IBasePickerProps<T> extends React.Props<any> { | |||
* @default false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a change request json file. Instructions:
- make sure you have an upstream remote to officedev url (I call mine "upstream")
npm run change -- --b upstream/master
This change is a "minor" package bump.
For comment, these show up in release notes. Please follow the convention ComponentName: change description
.
BasePicker: added
itemLimit property (etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ahh :) sorry about that.. done that now. Thanks.
protected okToAddMore(): boolean { | ||
const { items } = this.state; | ||
const { itemLimit } = this.props; | ||
if (typeof itemLimit !== 'undefined' && items.length === itemLimit) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor suggestion; this can be shortened to itemLimit !== undefined
. AFAIK you only really need to use typeof when you are checking if a global variable like document
exists (to prevent throwing) or you really care about the primitive type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, you can further shorten by not even comparing undefined and just returning the length comparison. There really isn't a need to check itemLimit undefined unless you expect items.length to also potentially be undefined.
return (
items.length === itemLimit
);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true.. will change..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just a thought.. performance wise...
checking for undefined on itemLimit would exit early and skip checking the length of items. a micro optimization granted, but is it worth keeping in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried the shortest version.
return items.length < itemLimit;
and it seems to break existing functionality, when running the tests, as itemLimit is not passed in in most cases.
I think we should go with
return itemLimit === undefined || items.length < itemLimit;
so, when its undefined, its canAddMore() === true
and when its defined, items.length
has to be less than itemLimit to return true..
@@ -234,6 +243,9 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent< | |||
if (newEl) { | |||
this.focusZone.focusElement(newEl); | |||
} | |||
} else if (!this.okToAddMore()) { | |||
(items[items.length - 1] as IPickerItemProps<T>).selected = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if items.length is 0, you would null ref here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm.. not so sure we would get into this branch if items.length is 0 unless itemLimit is set to 0, and then I'm not sure the set focus would be triggered..
Will write some tests and correct accordingly..
What if we log warning when usrer sets itemLimit to 0 and recommend using disabled instead? And default to 1 if it is set to 0?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wrote two tests and it seems like it should be ok, what do you think?
@@ -180,6 +180,15 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent< | |||
); | |||
} | |||
|
|||
protected okToAddMore(): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor suggestion; canAddItems
may be a better name. ("more" of what? "ok to" is also inconsistent)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree.
@@ -156,7 +156,7 @@ export class BasePicker<T, P extends IBasePickerProps<T>> extends BaseComponent< | |||
<SelectionZone selection={ this.selection } selectionMode={ SelectionMode.multiple }> | |||
<div className={ css('ms-BasePicker-text', styles.pickerText) } role={ 'list' }> | |||
{ this.renderItems() } | |||
<BaseAutoFill | |||
{ this.okToAddMore() && (<BaseAutoFill | |||
{ ...inputProps as any } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing I'm not quite sure about is where focus will wind up. Normally when you select something, focus is given back to the input, in this case the input won't exist any more. I think focus and selection should be given to the last item selected in the list. I think you'll need to put the check in componentwillupdate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what I'm trying to achieve on line 246-248, seems to me that resetFocus() handles focus being set correctly and is called from several places. you think I should put some check in in componentwillupdate as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I totally missed that, should be good.
I wrote a test to verify the last item picked was in focus when itemLimit was reached.. and discovered a flaw in my implementation.. Testing in the browser it seems that its given focus.. but pressing backspace or del at that moment causes an error, as the onBackspace method relies on the input being around. Im wondering if I should change the logic in the onBackspace, or if its a potential rabbit hole. and go with disabling the input instead on |
the test I wrote to validate that the last picked item had focus led me down a path of minor changes which are in commit cc8ee04, everything seems to work fine in the browser, but I could not get the test to function.. trying to find the focused element and comparing it to expected value does not seem to work. seems to be something in phantomjs. I think I can write a derived picker where I can pass in a render function and use it as a spy to pull out the element being set as focused?. |
Pull request checklist
$ npm run change
Description of changes