Skip to content

fix(select):change calculateOverlayOffsetY to address offset for small lists #9885

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

Merged
merged 6 commits into from
Feb 18, 2018

Conversation

timmoy
Copy link
Contributor

@timmoy timmoy commented Feb 11, 2018

Fixes #9751

Adds to the _calculateOverlayOffsetY function of select.ts to disable the offset for lists when an option is already selected.
Current implementation determines if the new functionality is enabled based on a new property disableOptionCentering. It is used by adding the text disableOptionCentering to the inside of the <mat-select> tag like you would for multiple.

Example of usage:

<mat-select multiple [(ngModel)]="currentPokemon"
          [required]="pokemonRequired" [disabled]="pokemonDisabled" #pokemonControl="ngModel" disableOptionCentering>
          <mat-option *ngFor="let creature of pokemon" [value]="creature.value">
            {{ creature.viewValue }}
          </mat-option>
        </mat-select>

list with offset:
select list large list offset

list without offset:
select list disable offset

@timmoy timmoy requested review from crisbeto and kara as code owners February 11, 2018 08:12
@googlebot googlebot added the cla: yes PR author has agreed to Google's Contributor License Agreement label Feb 11, 2018
Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

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

Any new functionality has to have unit tests.

@@ -1119,6 +1119,11 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
const maxOptionsDisplayed = Math.floor(SELECT_PANEL_MAX_HEIGHT / itemHeight);
let optionOffsetFromPanelTop: number;

// Disable offset for smaller lists by returning 0 as value to offset
if (this._getItemCount() <= maxOptionsDisplayed) {
Copy link
Member

Choose a reason for hiding this comment

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

This goes against the Material design spec and I'm expecting it to break a lot of tests once we get to syncing it in. I think it's fine to have a functionality to disable it, but it should be an input that the consumer can opt-out of.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the feedback. I've updated the code to use a custom property to disable the offset only if the consumer chooses to do so by specifying it as a custom property. If nothing is specified, then the offset is enabled by default.

@timmoy timmoy force-pushed the select-list-position branch from 0c8bfb7 to 2846d51 Compare February 12, 2018 06:01
@timmoy timmoy force-pushed the select-list-position branch from 2846d51 to d87b1d7 Compare February 12, 2018 06:23
@timmoy
Copy link
Contributor Author

timmoy commented Feb 12, 2018

I know the travis check is failing (screenshots below), but the errors seems to indicated a lost connection/time out and I'm unsure if this has to do with the code I'm introducing. Any help with the error messages would be much appreciated, thanks!

select-list-travis-errors

@@ -360,6 +360,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
this._multiple = coerceBooleanProperty(value);
}

/** Whether the user wants to disable the offset. */
@Input () disableOffset: string = '';
Copy link
Member

Choose a reason for hiding this comment

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

Should be a boolean.

@@ -1119,6 +1122,11 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
const maxOptionsDisplayed = Math.floor(SELECT_PANEL_MAX_HEIGHT / itemHeight);
let optionOffsetFromPanelTop: number;

// Disable offset for smaller lists by returning 0 as value to offset
if (this.disableOffset == 'true') {
Copy link
Member

Choose a reason for hiding this comment

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

After changing it to a boolean, this should be if (this.disableOffset).

@@ -360,6 +360,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
this._multiple = coerceBooleanProperty(value);
}

/** Whether the user wants to disable the offset. */
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure whether people looking at the documentation would know what offset this is referring to. What about calling it something like disableOptionCentering?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've made the changes you requested for the input:

  • changed type to boolean
  • changed name of the variable
  • changed the if statement check

Copy link
Member

Choose a reason for hiding this comment

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

Note that this comment will end up on the docs site. Something along the lines of "Whether to center the active option over the trigger" would be clearer.

@@ -1119,6 +1122,11 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
const maxOptionsDisplayed = Math.floor(SELECT_PANEL_MAX_HEIGHT / itemHeight);
let optionOffsetFromPanelTop: number;

// Disable offset for smaller lists by returning 0 as value to offset
if (this.disableOffset == 'true') {
return 0;
Copy link
Member

Choose a reason for hiding this comment

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

The new option still needs unit tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added a unit test with option centering disabled along with a component for testing it. I was thinking of adding it to the 'positioning' tests, but didn't do so to make it easier to add other cases.
I've run gulp test after adding it and the headless chrome returns all successful, but I'm not sure if there is a better way to test it.

<div [style.height.px]="heightBelow"></div>
`
})
class SelectWithoutOptionCentering {
Copy link
Member

Choose a reason for hiding this comment

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

Can you trim this component down only to the functionality necessary to test the new option? Alternatively you should be able to re-use some of the other test components.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've gone with trimming the component down and got rid of what I could. The @Input and unit test description have also been updated.

formField = fixture.debugElement.query(By.css('mat-form-field')).nativeElement;
}));

it('should align the first option with trigger text if option centering is disabled',
Copy link
Member

Choose a reason for hiding this comment

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

"Pizza" is the second option in this case. Also it may be clearer if it was something like it('should not align the active option with the trigger if centering is disabled').

@@ -360,6 +360,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
this._multiple = coerceBooleanProperty(value);
}

/** Whether the user wants to disable the offset. */
Copy link
Member

Choose a reason for hiding this comment

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

Note that this comment will end up on the docs site. Something along the lines of "Whether to center the active option over the trigger" would be clearer.

@@ -360,6 +360,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
this._multiple = coerceBooleanProperty(value);
}

/** Whether to center the active option over the trigger. */
@Input () disableOptionCentering: boolean = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you use coerceBooleanProperty() for this? (see above for examples)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the suggestion! I've implemented it and it seems to make it easier for the user to customize now.

@@ -1119,6 +1122,11 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
const maxOptionsDisplayed = Math.floor(SELECT_PANEL_MAX_HEIGHT / itemHeight);
let optionOffsetFromPanelTop: number;

// Disable offset for smaller lists by returning 0 as value to offset
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this comment is out of date now ("smaller lists")

Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

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

Good to go once the final set of feedback is addressed.

@@ -360,6 +360,9 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
this._multiple = coerceBooleanProperty(value);
}

/** Whether to center the active option over the trigger. */
@Input () disableOptionCentering: boolean = false;
Copy link
Member

Choose a reason for hiding this comment

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

Remove the extra space before @Input.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've updated it along with the changes @willshowell mentioned. It changes the way we use the new option so the unit test template has been adjusted accordingly.

Copy link
Member

@crisbeto crisbeto left a comment

Choose a reason for hiding this comment

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

LGTM

@crisbeto crisbeto added pr: lgtm action: merge The PR is ready for merge by the caretaker target: minor This PR is targeted for the next minor release labels Feb 15, 2018
@jelbourn jelbourn merged commit f38bcd9 into angular:master Feb 18, 2018
@timmoy timmoy deleted the select-list-position branch February 21, 2018 16:34
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 8, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
action: merge The PR is ready for merge by the caretaker cla: yes PR author has agreed to Google's Contributor License Agreement target: minor This PR is targeted for the next minor release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

mat-select: provide the way to freeze the position of the control when the drop down is open
5 participants