Skip to content
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

feat: nullability support #5094

Merged
merged 2 commits into from
Jun 21, 2017
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
4 changes: 2 additions & 2 deletions e2e/components/tabs-e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('tabs', () => {
*/
async function getFocusStates(elements: ElementArrayFinder) {
return elements.map(async (element) => {
let elementText = await element.getText();
let elementText = await element!.getText();
let activeText = await browser.driver.switchTo().activeElement().getText();

return activeText === elementText;
Expand All @@ -98,7 +98,7 @@ function getBodyActiveStates(elements: ElementArrayFinder) {
*/
async function getClassStates(elements: ElementArrayFinder, className: string) {
return elements.map(async (element) => {
let classes = await element.getAttribute('class');
let classes = await element!.getAttribute('class');
return classes.split(/ +/g).indexOf(className) >= 0;
});
}
1 change: 1 addition & 0 deletions e2e/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strictNullChecks": true,
"inlineSources": true,
"lib": ["es2015"],
"module": "commonjs",
Expand Down
1 change: 1 addition & 0 deletions src/cdk/tsconfig-build.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"stripInternal": false,
"experimentalDecorators": true,
"noUnusedParameters": true,
"strictNullChecks": true,
"importHelpers": true,
"newLine": "lf",
"module": "es2015",
Expand Down
5 changes: 5 additions & 0 deletions src/demo-app/checkbox/checkbox-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ export class MdCheckboxDemoNestedChecklist {

allComplete(task: Task): boolean {
let subtasks = task.subtasks;

if (!subtasks) {
return false;
}

return subtasks.every(t => t.completed) ? true
: subtasks.every(t => !t.completed) ? false
: task.completed;
Expand Down
4 changes: 2 additions & 2 deletions src/demo-app/data-table/data-table-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Component} from '@angular/core';
import {PeopleDatabase} from './people-database';
import {PersonDataSource} from './person-data-source';

export type UserProperties = 'userId' | 'userName' | 'progress' | 'color';
export type UserProperties = 'userId' | 'userName' | 'progress' | 'color' | undefined;

@Component({
moduleId: module.id,
Expand All @@ -11,7 +11,7 @@ export type UserProperties = 'userId' | 'userName' | 'progress' | 'color';
styleUrls: ['data-table-demo.css'],
})
export class DataTableDemo {
dataSource: PersonDataSource;
dataSource: PersonDataSource | null;
propertiesToDisplay: UserProperties[] = [];

constructor(private _peopleDatabase: PeopleDatabase) {
Expand Down
6 changes: 3 additions & 3 deletions src/demo-app/dialog/dialog-demo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component, Inject, ViewChild, TemplateRef} from '@angular/core';
import {DOCUMENT} from '@angular/platform-browser';
import {MdDialog, MdDialogRef, MdDialogConfig, MD_DIALOG_DATA} from '@angular/material';
import {MdDialog, MdDialogRef, MD_DIALOG_DATA} from '@angular/material';


@Component({
Expand All @@ -10,10 +10,10 @@ import {MdDialog, MdDialogRef, MdDialogConfig, MD_DIALOG_DATA} from '@angular/ma
styleUrls: ['dialog-demo.css'],
})
export class DialogDemo {
dialogRef: MdDialogRef<JazzDialog>;
dialogRef: MdDialogRef<JazzDialog> | null;
lastCloseResult: string;
actionsAlignment: string;
config: MdDialogConfig = {
config = {
disableClose: false,
panelClass: 'custom-overlay-pane-class',
hasBackdrop: true,
Expand Down
2 changes: 1 addition & 1 deletion src/demo-app/ripple/ripple-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class RippleDemo {
disabled = false;
unbounded = false;
rounded = false;
radius: number = null;
radius: number;
rippleSpeed = 1;
rippleColor = '';

Expand Down
4 changes: 2 additions & 2 deletions src/demo-app/snack-bar/snack-bar-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class SnackBarDemo {
open() {
let config = new MdSnackBarConfig();
config.duration = this.autoHide;
config.extraClasses = this.addExtraClass ? ['party'] : null;
this.snackBar.open(this.message, this.action && this.actionButtonLabel, config);
config.extraClasses = this.addExtraClass ? ['party'] : undefined;
this.snackBar.open(this.message, this.action ? this.actionButtonLabel : undefined, config);
}
}
3 changes: 2 additions & 1 deletion src/demo-app/tsconfig-aot.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// TypeScript config that extends the demo-app tsconfig file. This config compiles the
// TypeScript config that extends the demo-app tsconfig file. This config compiles the
// "main-aot.ts" file and also enables templage code generation / AOT. All paths need
// to be relative to the output directory.
{
Expand All @@ -7,6 +7,7 @@
"experimentalDecorators": true,
// TODO(paul): Remove once Angular has been upgraded and supports noUnusedParameters in AOT.
"noUnusedParameters": false,
"strictNullChecks": true,
"outDir": ".",
"paths": {
"@angular/material": ["./material"],
Expand Down
1 change: 1 addition & 0 deletions src/demo-app/tsconfig-build.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noUnusedParameters": true,
"strictNullChecks": true,
"lib": ["es6", "es2015", "dom"],
"module": "commonjs",
"moduleResolution": "node",
Expand Down
7 changes: 2 additions & 5 deletions src/e2e-app/dialog/dialog-e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,15 @@ import {MdDialog, MdDialogRef, MdDialogConfig} from '@angular/material';
templateUrl: 'dialog-e2e.html'
})
export class DialogE2E {
dialogRef: MdDialogRef<TestDialog>;
dialogRef: MdDialogRef<TestDialog> | null;

@ViewChild(TemplateRef) templateRef: TemplateRef<any>;

constructor (private _dialog: MdDialog) { }

private _openDialog(config?: MdDialogConfig) {
this.dialogRef = this._dialog.open(TestDialog, config);

this.dialogRef.afterClosed().subscribe(() => {
this.dialogRef = null;
});
this.dialogRef.afterClosed().subscribe(() => this.dialogRef = null);
}

openDefault() {
Expand Down
2 changes: 1 addition & 1 deletion src/e2e-app/fullscreen/fullscreen-e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {MdDialog, MdDialogRef} from '@angular/material';
})
export class FullscreenE2E {

dialogRef: MdDialogRef<TestDialog>;
dialogRef: MdDialogRef<TestDialog> | null;

constructor (private _element: ElementRef, private _dialog: MdDialog) { }

Expand Down
1 change: 1 addition & 0 deletions src/e2e-app/tsconfig-build.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"experimentalDecorators": true,
// TODO(paul): Remove once Angular has been upgraded and supports noUnusedParameters in AOT.
"noUnusedParameters": false,
"strictNullChecks": true,
"lib": ["es6", "es2015", "dom"],
"module": "commonjs",
"moduleResolution": "node",
Expand Down
21 changes: 13 additions & 8 deletions src/lib/autocomplete/autocomplete-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/observable/of';

/**
* The following style constants are necessary to save here in order
Expand Down Expand Up @@ -86,7 +87,7 @@ export function getMdAutocompleteMissingPanelError(): Error {
providers: [MD_AUTOCOMPLETE_VALUE_ACCESSOR]
})
export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
private _overlayRef: OverlayRef;
private _overlayRef: OverlayRef | null;
private _portal: TemplatePortal;
private _panelOpen: boolean = false;

Expand Down Expand Up @@ -153,7 +154,7 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
this._overlayRef.updateSize();
}

if (!this._overlayRef.hasAttached()) {
if (this._overlayRef && !this._overlayRef.hasAttached()) {
this._overlayRef.attach(this._portal);
this._subscribeToClosingActions();
}
Expand Down Expand Up @@ -197,10 +198,12 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
}

/** The currently active option, coerced to MdOption type. */
get activeOption(): MdOption {
get activeOption(): MdOption | null {
if (this.autocomplete && this.autocomplete._keyManager) {
return this.autocomplete._keyManager.activeItem as MdOption;
}

return null;
}

/** Stream of clicks outside of the autocomplete panel. */
Expand All @@ -214,9 +217,11 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
return this._panelOpen &&
clickTarget !== this._element.nativeElement &&
(!inputContainer || !inputContainer.contains(clickTarget)) &&
!this._overlayRef.overlayElement.contains(clickTarget);
(!!this._overlayRef && !this._overlayRef.overlayElement.contains(clickTarget));
});
}

return Observable.of(null);
}

/**
Expand Down Expand Up @@ -312,8 +317,8 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
* height, so the active option will be just visible at the bottom of the panel.
*/
private _scrollToOption(): void {
const optionOffset =
this.autocomplete._keyManager.activeItemIndex * AUTOCOMPLETE_OPTION_HEIGHT;
const optionOffset = this.autocomplete._keyManager.activeItemIndex ?
this.autocomplete._keyManager.activeItemIndex * AUTOCOMPLETE_OPTION_HEIGHT : 0;
const newScrollTop =
Math.max(0, optionOffset - AUTOCOMPLETE_PANEL_HEIGHT + AUTOCOMPLETE_OPTION_HEIGHT);
this.autocomplete._setScrollTop(newScrollTop);
Expand Down Expand Up @@ -419,9 +424,9 @@ export class MdAutocompleteTrigger implements ControlValueAccessor, OnDestroy {
return this._element.nativeElement.getBoundingClientRect().width;
}

/** Reset active item to null so arrow events will activate the correct options.*/
/** Reset active item to -1 so arrow events will activate the correct options.*/
private _resetActiveItem(): void {
this.autocomplete._keyManager.setActiveItem(null);
this.autocomplete._keyManager.setActiveItem(-1);
}

/**
Expand Down
24 changes: 12 additions & 12 deletions src/lib/autocomplete/autocomplete.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ describe('MdAutocomplete', () => {
// Note that we're running outside the Angular zone, in order to be able
// to test properly without the subscription from `_subscribeToClosingActions`
// giving us a false positive.
fixture.ngZone.runOutsideAngular(() => {
fixture.ngZone!.runOutsideAngular(() => {
fixture.componentInstance.trigger.openPanel();

Promise.resolve().then(() => {
Expand Down Expand Up @@ -328,7 +328,7 @@ describe('MdAutocomplete', () => {
rtlFixture.componentInstance.trigger.openPanel();
rtlFixture.detectChanges();

const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane');
const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane')!;
expect(overlayPane.getAttribute('dir')).toEqual('rtl');

});
Expand Down Expand Up @@ -731,7 +731,7 @@ describe('MdAutocomplete', () => {
it('should scroll to active options below the fold', fakeAsync(() => {
tick();
const scrollContainer =
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel');
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;

fixture.componentInstance.trigger._handleKeydown(DOWN_ARROW_EVENT);
tick();
Expand All @@ -752,7 +752,7 @@ describe('MdAutocomplete', () => {
it('should scroll to active options on UP arrow', fakeAsync(() => {
tick();
const scrollContainer =
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel');
document.querySelector('.cdk-overlay-pane .mat-autocomplete-panel')!;

const UP_ARROW_EVENT = createKeyboardEvent('keydown', UP_ARROW);
fixture.componentInstance.trigger._handleKeydown(UP_ARROW_EVENT);
Expand Down Expand Up @@ -934,7 +934,7 @@ describe('MdAutocomplete', () => {
fixture.detectChanges();

const inputBottom = input.getBoundingClientRect().bottom;
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel');
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel')!;
const panelTop = panel.getBoundingClientRect().top;

// Panel is offset by 6px in styles so that the underline has room to display.
Expand All @@ -958,7 +958,7 @@ describe('MdAutocomplete', () => {
fixture.detectChanges();

const inputBottom = input.getBoundingClientRect().bottom;
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel');
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel')!;
const panelTop = panel.getBoundingClientRect().top;

expect(Math.floor(inputBottom + 6)).toEqual(Math.floor(panelTop),
Expand All @@ -976,7 +976,7 @@ describe('MdAutocomplete', () => {
fixture.detectChanges();

const inputTop = input.getBoundingClientRect().top;
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel');
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel')!;
const panelBottom = panel.getBoundingClientRect().bottom;

// Panel is offset by 24px in styles so that the label has room to display.
Expand All @@ -999,7 +999,7 @@ describe('MdAutocomplete', () => {
fixture.detectChanges();

const inputTop = input.getBoundingClientRect().top;
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel');
const panel = overlayContainerElement.querySelector('.mat-autocomplete-panel')!;
const panelBottom = panel.getBoundingClientRect().bottom;

// Panel is offset by 24px in styles so that the label has room to display.
Expand Down Expand Up @@ -1182,7 +1182,7 @@ describe('MdAutocomplete', () => {

const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement;
// Firefox, edge return a decimal value for width, so we need to parse and round it to verify
expect(Math.ceil(parseFloat(overlayPane.style.width))).toBe(300);
expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(300);

widthFixture.componentInstance.trigger.closePanel();
widthFixture.detectChanges();
Expand All @@ -1194,7 +1194,7 @@ describe('MdAutocomplete', () => {
widthFixture.detectChanges();

// Firefox, edge return a decimal value for width, so we need to parse and round it to verify
expect(Math.ceil(parseFloat(overlayPane.style.width))).toBe(500);
expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(500);
});

it('should update the width while the panel is open', () => {
Expand All @@ -1209,7 +1209,7 @@ describe('MdAutocomplete', () => {
const overlayPane = overlayContainerElement.querySelector('.cdk-overlay-pane') as HTMLElement;
const input = widthFixture.debugElement.query(By.css('input')).nativeElement;

expect(Math.ceil(parseFloat(overlayPane.style.width))).toBe(300);
expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(300);

widthFixture.componentInstance.width = 500;
widthFixture.detectChanges();
Expand All @@ -1218,7 +1218,7 @@ describe('MdAutocomplete', () => {
dispatchFakeEvent(input, 'input');
widthFixture.detectChanges();

expect(Math.ceil(parseFloat(overlayPane.style.width))).toBe(500);
expect(Math.ceil(parseFloat(overlayPane.style.width as string))).toBe(500);
});

it('should show the panel when the options are initialized later within a component with ' +
Expand Down
2 changes: 1 addition & 1 deletion src/lib/autocomplete/autocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class MdAutocomplete implements AfterContentInit {
@ContentChildren(MdOption) options: QueryList<MdOption>;

/** Function that maps an option's control value to its display value in the trigger. */
@Input() displayWith: (value: any) => string;
@Input() displayWith: ((value: any) => string) | null = null;

/** Unique ID to be used by autocomplete trigger's "aria-owns" property. */
id: string = `md-autocomplete-${_uniqueAutocompleteIdCounter++}`;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/button-toggle/button-toggle.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[type]="_type"
[id]="inputId"
[checked]="checked"
[disabled]="disabled"
[disabled]="disabled || null"
[name]="name"
(change)="_onInputChange($event)"
(click)="_onInputClick($event)">
Expand Down
4 changes: 2 additions & 2 deletions src/lib/button-toggle/button-toggle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ describe('MdButtonToggle', () => {
for (let buttonToggle of buttonToggleInstances) {
expect(buttonToggle.checked).toBe(groupInstance.value === buttonToggle.value);
}
expect(groupInstance.selected.value).toBe(groupInstance.value);
expect(groupInstance.selected!.value).toBe(groupInstance.value);
});

it('should have the correct FormControl state initially and after interaction',
Expand Down Expand Up @@ -595,7 +595,7 @@ describe('MdButtonToggle', () => {
class ButtonTogglesInsideButtonToggleGroup {
isGroupDisabled: boolean = false;
isVertical: boolean = false;
groupValue: string = null;
groupValue: string;
}

@Component({
Expand Down
Loading