diff --git a/src/lib/select/select.scss b/src/lib/select/select.scss
index e616041dba76..937e8d37c86c 100644
--- a/src/lib/select/select.scss
+++ b/src/lib/select/select.scss
@@ -1,4 +1,5 @@
@import '../core/style/menu-common';
+@import '../core/style/list-common';
@import '../core/style/form-common';
@import '../a11y/_a11y';
@@ -63,6 +64,7 @@ md-select {
.md-select-value {
position: absolute;
+ @include md-truncate-line();
// Firefox and some versions of IE incorrectly keep absolutely
// positioned children of flex containers in the flex flow when calculating
diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts
index b10e7bd0a306..d93404c6733e 100644
--- a/src/lib/select/select.spec.ts
+++ b/src/lib/select/select.spec.ts
@@ -16,7 +16,7 @@ describe('MdSelect', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdSelectModule.forRoot(), ReactiveFormsModule, FormsModule],
- declarations: [BasicSelect, NgModelSelect, ManySelects],
+ declarations: [BasicSelect, NgModelSelect, ManySelects, NgIfSelect],
providers: [
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
@@ -96,14 +96,16 @@ describe('MdSelect', () => {
});
}));
- it('should set the width of the overlay based on the trigger', () => {
+ it('should set the width of the overlay based on the trigger', async(() => {
trigger.style.width = '200px';
- trigger.click();
- fixture.detectChanges();
- const pane = overlayContainerElement.children[0] as HTMLElement;
- expect(pane.style.width).toBe('200px');
- });
+ fixture.whenStable().then(() => {
+ trigger.click();
+ fixture.detectChanges();
+ const pane = overlayContainerElement.children[0] as HTMLElement;
+ expect(pane.style.minWidth).toBe('200px');
+ });
+ }));
});
@@ -997,6 +999,39 @@ describe('MdSelect', () => {
});
+ describe('special cases', () => {
+
+ it('should handle nesting in an ngIf', async(() => {
+ const fixture = TestBed.createComponent(NgIfSelect);
+ fixture.detectChanges();
+
+ fixture.componentInstance.isShowing = true;
+ fixture.detectChanges();
+
+ const trigger = fixture.debugElement.query(By.css('.md-select-trigger')).nativeElement;
+ trigger.style.width = '300px';
+
+ fixture.whenStable().then(() => {
+ fixture.detectChanges();
+ const value = fixture.debugElement.query(By.css('.md-select-value'));
+ expect(value.nativeElement.textContent)
+ .toContain('Pizza', `Expected trigger to be populated by the control's initial value.`);
+
+ trigger.click();
+ fixture.detectChanges();
+
+ const pane = overlayContainerElement.children[0] as HTMLElement;
+ expect(pane.style.minWidth).toEqual('300px');
+
+ expect(fixture.componentInstance.select.panelOpen).toBe(true);
+ expect(overlayContainerElement.textContent).toContain('Steak');
+ expect(overlayContainerElement.textContent).toContain('Pizza');
+ expect(overlayContainerElement.textContent).toContain('Tacos');
+ });
+ }));
+
+ });
+
});
@Component({
@@ -1062,6 +1097,32 @@ class NgModelSelect {
})
class ManySelects {}
+@Component({
+ selector: 'ng-if-select',
+ template: `
+
+
+
+ {{ food.viewValue }}
+
+
+
+ `
+
+})
+class NgIfSelect {
+ isShowing = false;
+ foods: any[] = [
+ { value: 'steak-0', viewValue: 'Steak' },
+ { value: 'pizza-1', viewValue: 'Pizza' },
+ { value: 'tacos-2', viewValue: 'Tacos'}
+ ];
+ control = new FormControl('pizza-1');
+
+ @ViewChild(MdSelect) select: MdSelect;
+}
+
+
/**
* TODO: Move this to core testing utility until Angular has event faking
diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts
index 4820f180bf57..e4b2eb936a4c 100644
--- a/src/lib/select/select.ts
+++ b/src/lib/select/select.ts
@@ -114,9 +114,24 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
/** The scroll position of the overlay panel, calculated to center the selected option. */
private _scrollTop = 0;
+ /** The placeholder displayed in the trigger of the select. */
+ private _placeholder: string;
+
/** The animation state of the placeholder. */
_placeholderState = '';
+ /**
+ * The width of the trigger. Must be saved to set the min width of the overlay panel
+ * and the width of the selected value.
+ */
+ _triggerWidth: number;
+
+ /**
+ * The width of the selected option's value. Must be set programmatically
+ * to ensure its overflow is clipped, as it's absolutely positioned.
+ */
+ _selectedValueWidth: number;
+
/** Manages keyboard events for options in the panel. */
_keyManager: ListKeyManager;
@@ -171,7 +186,17 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
@ViewChild(ConnectedOverlayDirective) overlayDir: ConnectedOverlayDirective;
@ContentChildren(MdOption) options: QueryList
;
- @Input() placeholder: string;
+ @Input()
+ get placeholder() {
+ return this._placeholder;
+ }
+
+ set placeholder(value: string) {
+ this._placeholder = value;
+
+ // Must wait to record the trigger width to ensure placeholder width is included.
+ Promise.resolve(null).then(() => this._triggerWidth = this._getWidth());
+ }
@Input()
get disabled() {
@@ -400,6 +425,7 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
private _onSelect(option: MdOption): void {
this._selected = option;
this._updateOptions();
+ this._setValueWidth();
if (this.panelOpen) {
this.close();
}
@@ -414,6 +440,15 @@ export class MdSelect implements AfterContentInit, ControlValueAccessor, OnDestr
});
}
+ /**
+ * Must set the width of the selected option's value programmatically
+ * because it is absolutely positioned and otherwise will not clip
+ * overflow. The selection arrow is 9px wide, add 4px of padding = 13
+ */
+ private _setValueWidth() {
+ this._selectedValueWidth = this._triggerWidth - 13;
+ }
+
/** Focuses the selected item. If no option is selected, it will focus
* the first item instead.
*/