feat: remove the need for forRoot on material NgModules (#2556)

This commit is contained in:
Jeremy Elbourn
2017-01-10 17:22:42 -08:00
committed by tinayuangao
parent fed5d7b63c
commit b49bfce5a9
45 changed files with 366 additions and 83 deletions
+1
View File
@@ -15,6 +15,7 @@ export * from './autocomplete-trigger';
declarations: [MdAutocomplete, MdAutocompleteTrigger],
})
export class MdAutocompleteModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdAutocompleteModule,
+4 -1
View File
@@ -24,6 +24,7 @@ import {
UniqueSelectionDispatcher,
coerceBooleanProperty,
DefaultStyleCompatibilityModeModule,
UNIQUE_SELECTION_DISPATCHER_PROVIDER,
} from '../core';
/** Acceptable types for a button toggle. */
@@ -471,12 +472,14 @@ export class MdButtonToggle implements OnInit {
DefaultStyleCompatibilityModeModule,
],
declarations: [MdButtonToggleGroup, MdButtonToggleGroupMultiple, MdButtonToggle],
providers: [UNIQUE_SELECTION_DISPATCHER_PROVIDER]
})
export class MdButtonToggleModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdButtonToggleModule,
providers: [UniqueSelectionDispatcher]
providers: []
};
}
}
+2 -2
View File
@@ -11,7 +11,6 @@ import {
} from '@angular/core';
import {CommonModule} from '@angular/common';
import {MdRippleModule, coerceBooleanProperty, DefaultStyleCompatibilityModeModule} from '../core';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
// TODO(jelbourn): Make the `isMouseDown` stuff done with one global listener.
@@ -167,10 +166,11 @@ export class MdAnchor extends MdButton {
declarations: [MdButton, MdAnchor],
})
export class MdButtonModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdButtonModule,
providers: [ViewportRuler]
providers: []
};
}
}
+1
View File
@@ -119,6 +119,7 @@ export class MdCardTitleGroup {}
],
})
export class MdCardModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdCardModule,
+2 -2
View File
@@ -17,7 +17,6 @@ import {CommonModule} from '@angular/common';
import {NG_VALUE_ACCESSOR, ControlValueAccessor} from '@angular/forms';
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
import {MdRippleModule, DefaultStyleCompatibilityModeModule} from '../core';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
/** Monotonically increasing integer used to auto-generate unique ids for checkbox components. */
@@ -399,10 +398,11 @@ export class MdCheckbox implements ControlValueAccessor {
declarations: [MdCheckbox],
})
export class MdCheckboxModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdCheckboxModule,
providers: [ViewportRuler]
providers: []
};
}
}
+1
View File
@@ -215,6 +215,7 @@ export class MdChipList implements AfterContentInit {
declarations: [MdChipList, MdChip]
})
export class MdChipsModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdChipsModule,
+4 -7
View File
@@ -1,25 +1,22 @@
import {NgModule, ModuleWithProviders} from '@angular/core';
import {FocusTrap} from './focus-trap';
import {LiveAnnouncer} from './live-announcer';
import {LIVE_ANNOUNCER_PROVIDER} from './live-announcer';
import {InteractivityChecker} from './interactivity-checker';
import {CommonModule} from '@angular/common';
import {PlatformModule} from '../platform/index';
export const A11Y_PROVIDERS = [LiveAnnouncer, InteractivityChecker];
@NgModule({
imports: [CommonModule, PlatformModule],
declarations: [FocusTrap],
exports: [FocusTrap],
providers: [InteractivityChecker, LIVE_ANNOUNCER_PROVIDER]
})
export class A11yModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: A11yModule,
providers: [
PlatformModule.forRoot().providers,
A11Y_PROVIDERS,
],
providers: [],
};
}
}
-1
View File
@@ -115,4 +115,3 @@ class TestApp {
this.live.announce(message);
}
}
+16 -1
View File
@@ -2,7 +2,8 @@ import {
Injectable,
OpaqueToken,
Optional,
Inject
Inject,
SkipSelf,
} from '@angular/core';
export const LIVE_ANNOUNCER_ELEMENT_TOKEN = new OpaqueToken('liveAnnouncerElement');
@@ -62,3 +63,17 @@ export class LiveAnnouncer {
}
}
export function LIVE_ANNOUNCER_PROVIDER_FACTORY(parentDispatcher: LiveAnnouncer, liveElement: any) {
return parentDispatcher || new LiveAnnouncer(liveElement);
};
export const LIVE_ANNOUNCER_PROVIDER = {
// If there is already a LiveAnnouncer available, use that. Otherwise, provide a new one.
provide: LiveAnnouncer,
deps: [
[new Optional(), new SkipSelf(), LiveAnnouncer],
[new Optional(), new Inject(LIVE_ANNOUNCER_ELEMENT_TOKEN)]
],
useFactory: LIVE_ANNOUNCER_PROVIDER_FACTORY
};
@@ -71,6 +71,7 @@ export class MatPrefixEnforcer {
}]
})
export class DefaultStyleCompatibilityModeModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: DefaultStyleCompatibilityModeModule,
@@ -60,6 +60,7 @@ export class MdPrefixEnforcer {
}],
})
export class NoConflictStyleCompatibilityMode {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: NoConflictStyleCompatibilityMode,
@@ -1,4 +1,4 @@
import {Injectable} from '@angular/core';
import {Injectable, Optional, SkipSelf} from '@angular/core';
// Users of the Dispatcher never need to see this type, but TypeScript requires it to be exported.
@@ -33,3 +33,15 @@ export class UniqueSelectionDispatcher {
this._listeners.push(listener);
}
}
export function UNIQUE_SELECTION_DISPATCHER_PROVIDER_FACTORY(
parentDispatcher: UniqueSelectionDispatcher) {
return parentDispatcher || new UniqueSelectionDispatcher();
}
export const UNIQUE_SELECTION_DISPATCHER_PROVIDER = {
// If there is already a dispatcher available, use that. Otherwise, provide a new one.
provide: UniqueSelectionDispatcher,
deps: [[new Optional(), new SkipSelf(), UniqueSelectionDispatcher]],
useFactory: UNIQUE_SELECTION_DISPATCHER_PROVIDER_FACTORY
};
+6 -6
View File
@@ -6,8 +6,7 @@ import {MdOptionModule} from './option/option';
import {MdRippleModule} from './ripple/ripple';
import {PortalModule} from './portal/portal-directives';
import {OverlayModule} from './overlay/overlay-directives';
import {A11yModule, A11Y_PROVIDERS} from './a11y/index';
import {OVERLAY_PROVIDERS} from './overlay/overlay';
import {A11yModule} from './a11y/index';
// RTL
@@ -71,8 +70,8 @@ export {
AriaLivePoliteness,
LiveAnnouncer,
LIVE_ANNOUNCER_ELEMENT_TOKEN,
LIVE_ANNOUNCER_PROVIDER,
} from './a11y/live-announcer';
/** @deprecated */
export {LiveAnnouncer as MdLiveAnnouncer} from './a11y/live-announcer';
@@ -84,9 +83,9 @@ export {A11yModule} from './a11y/index';
export {
UniqueSelectionDispatcher,
UniqueSelectionDispatcherListener
UniqueSelectionDispatcherListener,
UNIQUE_SELECTION_DISPATCHER_PROVIDER,
} from './coordination/unique-selection-dispatcher';
/** @deprecated */
export {
UniqueSelectionDispatcher as MdUniqueSelectionDispatcher
@@ -143,10 +142,11 @@ export {NoConflictStyleCompatibilityMode} from './compatibility/no-conflict-mode
],
})
export class MdCoreModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdCoreModule,
providers: [A11Y_PROVIDERS, OVERLAY_PROVIDERS],
providers: [],
};
}
}
@@ -46,6 +46,7 @@ export class ObserveContent implements AfterContentInit, OnDestroy {
declarations: [ObserveContent]
})
export class ObserveContentModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: ObserveContentModule,
+13 -1
View File
@@ -1,4 +1,5 @@
import {Injectable} from '@angular/core';
import {Injectable, Optional, SkipSelf} from '@angular/core';
/**
* The OverlayContainer is the container in which all overlays will load.
@@ -30,3 +31,14 @@ export class OverlayContainer {
this._containerElement = container;
}
}
export function OVERLAY_CONTAINER_PROVIDER_FACTORY(parentContainer: OverlayContainer) {
return parentContainer || new OverlayContainer();
};
export const OVERLAY_CONTAINER_PROVIDER = {
// If there is already an OverlayContainer available, use that. Otherwise, provide a new one.
provide: OverlayContainer,
deps: [[new Optional(), new SkipSelf(), OverlayContainer]],
useFactory: OVERLAY_CONTAINER_PROVIDER_FACTORY
};
+3 -1
View File
@@ -295,12 +295,14 @@ export class ConnectedOverlayDirective implements OnDestroy {
imports: [PortalModule],
exports: [ConnectedOverlayDirective, OverlayOrigin, Scrollable],
declarations: [ConnectedOverlayDirective, OverlayOrigin, Scrollable],
providers: [OVERLAY_PROVIDERS],
})
export class OverlayModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: OverlayModule,
providers: OVERLAY_PROVIDERS,
providers: [],
};
}
}
+10 -8
View File
@@ -4,14 +4,16 @@ import {
ApplicationRef,
Injector,
NgZone,
Provider,
} from '@angular/core';
import {OverlayState} from './overlay-state';
import {DomPortalHost} from '../portal/dom-portal-host';
import {OverlayRef} from './overlay-ref';
import {OverlayPositionBuilder} from './position/overlay-position-builder';
import {ViewportRuler} from './position/viewport-ruler';
import {OverlayContainer} from './overlay-container';
import {ScrollDispatcher} from './scroll/scroll-dispatcher';
import {VIEWPORT_RULER_PROVIDER} from './position/viewport-ruler';
import {OverlayContainer, OVERLAY_CONTAINER_PROVIDER} from './overlay-container';
import {SCROLL_DISPATCHER_PROVIDER} from './scroll/scroll-dispatcher';
/** Next overlay unique ID. */
let nextUniqueId = 0;
@@ -88,10 +90,10 @@ export class Overlay {
}
/** Providers for Overlay and its related injectables. */
export const OVERLAY_PROVIDERS = [
ViewportRuler,
OverlayPositionBuilder,
export const OVERLAY_PROVIDERS: Provider[] = [
Overlay,
OverlayContainer,
ScrollDispatcher,
OverlayPositionBuilder,
VIEWPORT_RULER_PROVIDER,
SCROLL_DISPATCHER_PROVIDER,
OVERLAY_CONTAINER_PROVIDER,
];
@@ -1,5 +1,4 @@
import {Injectable} from '@angular/core';
import {Injectable, Optional, SkipSelf} from '@angular/core';
/**
@@ -56,3 +55,14 @@ export class ViewportRuler {
return {top, left};
}
}
export function VIEWPORT_RULER_PROVIDER_FACTORY(parentDispatcher: ViewportRuler) {
return parentDispatcher || new ViewportRuler();
};
export const VIEWPORT_RULER_PROVIDER = {
// If there is already a ViewportRuler available, use that. Otherwise, provide a new one.
provide: ViewportRuler,
deps: [[new Optional(), new SkipSelf(), ViewportRuler]],
useFactory: VIEWPORT_RULER_PROVIDER_FACTORY
};
@@ -1,4 +1,4 @@
import {Injectable, ElementRef} from '@angular/core';
import {Injectable, ElementRef, Optional, SkipSelf} from '@angular/core';
import {Scrollable} from './scrollable';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
@@ -88,3 +88,13 @@ export class ScrollDispatcher {
}
}
export function SCROLL_DISPATCHER_PROVIDER_FACTORY(parentDispatcher: ScrollDispatcher) {
return parentDispatcher || new ScrollDispatcher();
};
export const SCROLL_DISPATCHER_PROVIDER = {
// If there is already a ScrollDispatcher available, use that. Otherwise, provide a new one.
provide: ScrollDispatcher,
deps: [[new Optional(), new SkipSelf(), ScrollDispatcher]],
useFactory: SCROLL_DISPATCHER_PROVIDER_FACTORY
};
+5 -2
View File
@@ -5,12 +5,15 @@ export * from './platform';
export * from './features';
@NgModule({})
@NgModule({
providers: [Platform]
})
export class PlatformModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: PlatformModule,
providers: [Platform],
providers: [],
};
}
}
+1
View File
@@ -130,6 +130,7 @@ export class PortalHostDirective extends BasePortalHost implements OnDestroy {
declarations: [TemplatePortalDirective, PortalHostDirective],
})
export class PortalModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: PortalModule,
+2 -1
View File
@@ -81,12 +81,13 @@ export class DomProjection {
@NgModule({
exports: [DomProjectionHost],
declarations: [DomProjectionHost],
providers: [DomProjection],
})
export class ProjectionModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: ProjectionModule,
providers: [DomProjection]
};
}
}
+4 -2
View File
@@ -17,7 +17,7 @@ import {
ForegroundRippleState,
} from './ripple-renderer';
import {DefaultStyleCompatibilityModeModule} from '../compatibility/default-mode';
import {ViewportRuler} from '../overlay/position/viewport-ruler';
import {ViewportRuler, VIEWPORT_RULER_PROVIDER} from '../overlay/position/viewport-ruler';
@Directive({
@@ -238,12 +238,14 @@ export class MdRipple implements OnInit, OnDestroy, OnChanges {
imports: [DefaultStyleCompatibilityModeModule],
exports: [MdRipple, DefaultStyleCompatibilityModeModule],
declarations: [MdRipple],
providers: [VIEWPORT_RULER_PROVIDER],
})
export class MdRippleModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdRippleModule,
providers: [ViewportRuler]
providers: []
};
}
}
+1
View File
@@ -52,6 +52,7 @@ export class Dir {
declarations: [Dir]
})
export class RtlModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: RtlModule,
+70
View File
@@ -346,6 +346,68 @@ describe('MdDialog', () => {
});
});
describe('MdDialog with a parent MdDialog', () => {
let parentDialog: MdDialog;
let childDialog: MdDialog;
let overlayContainerElement: HTMLElement;
let fixture: ComponentFixture<ComponentThatProvidesMdDialog>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdDialogModule.forRoot(), DialogTestModule],
declarations: [ComponentThatProvidesMdDialog],
providers: [
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
return {getContainerElement: () => overlayContainerElement};
}}
],
});
TestBed.compileComponents();
}));
beforeEach(inject([MdDialog], (d: MdDialog) => {
parentDialog = d;
fixture = TestBed.createComponent(ComponentThatProvidesMdDialog);
childDialog = fixture.componentInstance.dialog;
fixture.detectChanges();
}));
afterEach(() => {
overlayContainerElement.innerHTML = '';
});
it('should close dialogs opened by a parent when calling closeAll on a child MdDialog', () => {
parentDialog.open(PizzaMsg);
fixture.detectChanges();
expect(overlayContainerElement.textContent)
.toContain('Pizza', 'Expected a dialog to be opened');
childDialog.closeAll();
fixture.detectChanges();
expect(overlayContainerElement.textContent.trim())
.toBe('', 'Expected closeAll on child MdDialog to close dialog opened by parent');
});
it('should close dialogs opened by a child when calling closeAll on a parent MdDialog', () => {
childDialog.open(PizzaMsg);
fixture.detectChanges();
expect(overlayContainerElement.textContent)
.toContain('Pizza', 'Expected a dialog to be opened');
parentDialog.closeAll();
fixture.detectChanges();
expect(overlayContainerElement.textContent.trim())
.toBe('', 'Expected closeAll on parent MdDialog to close dialog opened by child');
});
});
@Directive({selector: 'dir-with-view-container'})
class DirectiveWithViewContainer {
@@ -384,6 +446,14 @@ class ContentElementDialog {
closeButtonAriaLabel: string;
}
@Component({
template: '',
providers: [MdDialog]
})
class ComponentThatProvidesMdDialog {
constructor(public dialog: MdDialog) {}
}
// Create a real (non-test) NgModule as a workaround for
// https://github.com/angular/angular/issues/10760
const TEST_DIRECTIVES = [
+11 -4
View File
@@ -1,4 +1,4 @@
import {Injector, ComponentRef, Injectable} from '@angular/core';
import {Injector, ComponentRef, Injectable, Optional, SkipSelf} from '@angular/core';
import {Overlay, OverlayRef, ComponentType, OverlayState, ComponentPortal} from '../core';
import {extendObject} from '../core/util/object-extend';
@@ -19,10 +19,17 @@ import {MdDialogContainer} from './dialog-container';
*/
@Injectable()
export class MdDialog {
/** Keeps track of the currently-open dialogs. */
private _openDialogs: MdDialogRef<any>[] = [];
private _openDialogsAtThisLevel: MdDialogRef<any>[] = [];
constructor(private _overlay: Overlay, private _injector: Injector) { }
/** Keeps track of the currently-open dialogs. */
get _openDialogs(): MdDialogRef<any>[] {
return this._parentDialog ? this._parentDialog._openDialogs : this._openDialogsAtThisLevel;
}
constructor(
private _overlay: Overlay,
private _injector: Injector,
@Optional() @SkipSelf() private _parentDialog: MdDialog) { }
/**
* Opens a modal dialog containing the given component.
+6 -6
View File
@@ -2,13 +2,9 @@ import {NgModule, ModuleWithProviders} from '@angular/core';
import {
OverlayModule,
PortalModule,
OVERLAY_PROVIDERS,
A11yModule,
InteractivityChecker,
Platform,
DefaultStyleCompatibilityModeModule,
DefaultStyleCompatibilityModeModule
} from '../core';
import {MdDialog} from './dialog';
import {MdDialogContainer} from './dialog-container';
import {
@@ -41,13 +37,17 @@ import {
MdDialogActions,
MdDialogContent
],
providers: [
MdDialog,
],
entryComponents: [MdDialogContainer],
})
export class MdDialogModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdDialogModule,
providers: [MdDialog, OVERLAY_PROVIDERS, InteractivityChecker, Platform],
providers: [],
};
}
}
+1
View File
@@ -156,6 +156,7 @@ export class MdGridList implements OnInit, AfterContentChecked {
declarations: [MdGridList, MdGridTile, MdGridTileText],
})
export class MdGridListModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdGridListModule,
+18 -2
View File
@@ -11,8 +11,11 @@ import {
SimpleChange,
ViewEncapsulation,
AfterViewChecked,
Optional,
SkipSelf,
} from '@angular/core';
import {HttpModule} from '@angular/http';
import {HttpModule, Http} from '@angular/http';
import {DomSanitizer} from '@angular/platform-browser';
import {MdError, DefaultStyleCompatibilityModeModule} from '../core';
import {MdIconRegistry} from './icon-registry';
export {MdIconRegistry} from './icon-registry';
@@ -244,17 +247,30 @@ export class MdIcon implements OnChanges, OnInit, AfterViewChecked {
}
}
export function ICON_REGISTRY_PROVIDER_FACTORY(
parentRegistry: MdIconRegistry, http: Http, sanitizer: DomSanitizer) {
return parentRegistry || new MdIconRegistry(http, sanitizer);
};
export const ICON_REGISTRY_PROVIDER = {
// If there is already an MdIconRegistry available, use that. Otherwise, provide a new one.
provide: MdIconRegistry,
deps: [[new Optional(), new SkipSelf(), MdIconRegistry], Http, DomSanitizer],
useFactory: ICON_REGISTRY_PROVIDER_FACTORY,
};
@NgModule({
imports: [HttpModule, DefaultStyleCompatibilityModeModule],
exports: [MdIcon, DefaultStyleCompatibilityModeModule],
declarations: [MdIcon],
providers: [ICON_REGISTRY_PROVIDER],
})
export class MdIconModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdIconModule,
providers: [MdIconRegistry],
providers: [],
};
}
}
+2 -1
View File
@@ -430,10 +430,11 @@ export class MdInput implements ControlValueAccessor, AfterContentInit, OnChange
],
})
export class MdInputModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdInputModule,
providers: PlatformModule.forRoot().providers,
providers: [],
};
}
}
+1
View File
@@ -84,6 +84,7 @@ export class MdListItem implements AfterContentInit {
declarations: [MdList, MdListItem, MdListDivider, MdListAvatar],
})
export class MdListModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdListModule,
+3 -2
View File
@@ -1,6 +1,6 @@
import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
import {OverlayModule, OVERLAY_PROVIDERS, DefaultStyleCompatibilityModeModule} from '../core';
import {OverlayModule, DefaultStyleCompatibilityModeModule} from '../core';
import {MdMenu} from './menu-directive';
import {MdMenuItem} from './menu-item';
import {MdMenuTrigger} from './menu-trigger';
@@ -18,10 +18,11 @@ export {MenuPositionX, MenuPositionY} from './menu-positions';
declarations: [MdMenu, MdMenuItem, MdMenuTrigger],
})
export class MdMenuModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdMenuModule,
providers: OVERLAY_PROVIDERS,
providers: [],
};
}
}
+1
View File
@@ -118,6 +118,7 @@ export class MaterialRootModule { }
exports: MATERIAL_MODULES,
})
export class MaterialModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {ngModule: MaterialRootModule};
}
+1
View File
@@ -91,6 +91,7 @@ function clamp(v: number, min = 0, max = 100) {
declarations: [MdProgressBar],
})
export class MdProgressBarModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdProgressBarModule,
@@ -367,6 +367,7 @@ function getSvgArc(currentValue: number, rotation: number) {
declarations: [MdProgressSpinner, MdSpinner],
})
export class MdProgressSpinnerModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdProgressSpinnerModule,
+5 -2
View File
@@ -24,9 +24,10 @@ import {
MdRippleModule,
UniqueSelectionDispatcher,
DefaultStyleCompatibilityModeModule,
UNIQUE_SELECTION_DISPATCHER_PROVIDER,
} from '../core';
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
import {VIEWPORT_RULER_PROVIDER} from '../core/overlay/position/viewport-ruler';
/**
@@ -508,13 +509,15 @@ export class MdRadioButton implements OnInit {
@NgModule({
imports: [CommonModule, MdRippleModule, DefaultStyleCompatibilityModeModule],
exports: [MdRadioGroup, MdRadioButton, DefaultStyleCompatibilityModeModule],
providers: [UNIQUE_SELECTION_DISPATCHER_PROVIDER, VIEWPORT_RULER_PROVIDER],
declarations: [MdRadioGroup, MdRadioButton],
})
export class MdRadioModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdRadioModule,
providers: [UniqueSelectionDispatcher, ViewportRuler],
providers: [],
};
}
}
+2 -2
View File
@@ -4,7 +4,6 @@ import {MdSelect} from './select';
import {MdOptionModule} from '../core/option/option';
import {
DefaultStyleCompatibilityModeModule,
OVERLAY_PROVIDERS,
OverlayModule,
} from '../core';
export * from './select';
@@ -17,10 +16,11 @@ export {fadeInContent, transformPanel, transformPlaceholder} from './select-anim
declarations: [MdSelect],
})
export class MdSelectModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdSelectModule,
providers: [OVERLAY_PROVIDERS]
providers: []
};
}
}
+2 -2
View File
@@ -21,7 +21,6 @@ import {A11yModule} from '../core/a11y/index';
import {FocusTrap} from '../core/a11y/focus-trap';
import {ESCAPE} from '../core/keyboard/keycodes';
import {OverlayModule} from '../core/overlay/overlay-directives';
import {InteractivityChecker} from '../core/a11y/interactivity-checker';
/** Exception thrown when two MdSidenav are matching the same side. */
@@ -512,10 +511,11 @@ export class MdSidenavContainer implements AfterContentInit {
declarations: [MdSidenavContainer, MdSidenav],
})
export class MdSidenavModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdSidenavModule,
providers: [InteractivityChecker]
providers: []
};
}
}
+3 -1
View File
@@ -337,12 +337,14 @@ class SlideToggleRenderer {
imports: [FormsModule, DefaultStyleCompatibilityModeModule],
exports: [MdSlideToggle, DefaultStyleCompatibilityModeModule],
declarations: [MdSlideToggle],
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}],
})
export class MdSlideToggleModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdSlideToggleModule,
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}]
providers: []
};
}
}
+3 -4
View File
@@ -579,15 +579,14 @@ export class SliderRenderer {
imports: [CommonModule, FormsModule, DefaultStyleCompatibilityModeModule],
exports: [MdSlider, DefaultStyleCompatibilityModeModule],
declarations: [MdSlider],
providers: [
{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig},
],
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}]
})
export class MdSliderModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdSliderModule,
providers: [{provide: HAMMER_GESTURE_CONFIG, useClass: GestureConfig}]
providers: []
};
}
}
+77 -2
View File
@@ -5,7 +5,7 @@ import {
TestBed,
fakeAsync,
flushMicrotasks,
tick,
tick
} from '@angular/core/testing';
import {NgModule, Component, Directive, ViewChild, ViewContainerRef} from '@angular/core';
import {CommonModule} from '@angular/common';
@@ -307,7 +307,7 @@ describe('MdSnackBar', () => {
let config = new MdSnackBarConfig();
config.duration = 250;
let snackBarRef = snackBar.open('content', 'test', config);
snackBarRef.afterDismissed().subscribe(null, null, () => {
snackBarRef.afterDismissed().subscribe(() => {
dismissObservableCompleted = true;
});
@@ -322,6 +322,72 @@ describe('MdSnackBar', () => {
}));
});
describe('MdSbackBar with parent MdSnackBar', () => {
let parentSnackBar: MdSnackBar;
let childSnackBar: MdSnackBar;
let overlayContainerElement: HTMLElement;
let fixture: ComponentFixture<ComponentThatProvidesMdSnackBar>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [MdSnackBarModule.forRoot(), SnackBarTestModule],
declarations: [ComponentThatProvidesMdSnackBar],
providers: [
{provide: OverlayContainer, useFactory: () => {
overlayContainerElement = document.createElement('div');
return {getContainerElement: () => overlayContainerElement};
}}
],
});
TestBed.compileComponents();
}));
beforeEach(inject([MdSnackBar], (sb: MdSnackBar) => {
parentSnackBar = sb;
fixture = TestBed.createComponent(ComponentThatProvidesMdSnackBar);
childSnackBar = fixture.componentInstance.snackBar;
fixture.detectChanges();
}));
afterEach(() => {
overlayContainerElement.innerHTML = '';
});
it('should close snackBars opened by parent when opening from child MdSnackBar', fakeAsync(() => {
parentSnackBar.open('Pizza');
fixture.detectChanges();
tick(1000);
expect(overlayContainerElement.textContent)
.toContain('Pizza', 'Expected a snackBar to be opened');
childSnackBar.open('Taco');
fixture.detectChanges();
tick(1000);
expect(overlayContainerElement.textContent)
.toContain('Taco', 'Expected parent snackbar msg to be dismissed by opening from child');
}));
it('should close snackBars opened by child when opening from parent MdSnackBar', fakeAsync(() => {
childSnackBar.open('Pizza');
fixture.detectChanges();
tick(1000);
expect(overlayContainerElement.textContent)
.toContain('Pizza', 'Expected a snackBar to be opened');
parentSnackBar.open('Taco');
fixture.detectChanges();
tick(1000);
expect(overlayContainerElement.textContent)
.toContain('Taco', 'Expected child snackbar msg to be dismissed by opening from parent');
}));
});
@Directive({selector: 'dir-with-view-container'})
class DirectiveWithViewContainer {
constructor(public viewContainerRef: ViewContainerRef) { }
@@ -346,6 +412,15 @@ class ComponentWithChildViewContainer {
class BurritosNotification {}
@Component({
template: '',
providers: [MdSnackBar]
})
class ComponentThatProvidesMdSnackBar {
constructor(public snackBar: MdSnackBar) {}
}
/** Simple component to open snack bars from.
* Create a real (non-test) NgModule as a workaround forRoot
* https://github.com/angular/angular/issues/10760
+37 -12
View File
@@ -3,6 +3,8 @@ import {
ModuleWithProviders,
Injectable,
ComponentRef,
Optional,
SkipSelf,
} from '@angular/core';
import {
ComponentType,
@@ -12,9 +14,9 @@ import {
OverlayRef,
OverlayState,
PortalModule,
OVERLAY_PROVIDERS,
LiveAnnouncer,
DefaultStyleCompatibilityModeModule,
LIVE_ANNOUNCER_PROVIDER,
} from '../core';
import {CommonModule} from '@angular/common';
import {MdSnackBarConfig} from './snack-bar-config';
@@ -29,10 +31,31 @@ import {extendObject} from '../core/util/object-extend';
*/
@Injectable()
export class MdSnackBar {
/** A reference to the current snack bar in the view. */
private _snackBarRef: MdSnackBarRef<any>;
/**
* Reference to the current snack bar in the view *at this level* (in the Angular injector tree).
* If there is a parent snack-bar service, all operations should delegate to that parent
* via `_openedSnackBarRef`.
*/
private _snackBarRefAtThisLevel: MdSnackBarRef<any>;
constructor(private _overlay: Overlay, private _live: LiveAnnouncer) {}
/** Reference to the currently opened snackbar at *any* level. */
get _openedSnackBarRef(): MdSnackBarRef<any> {
return this._parentSnackBar ?
this._parentSnackBar._openedSnackBarRef : this._snackBarRefAtThisLevel;
}
set _openedSnackBarRef(value: MdSnackBarRef<any>) {
if (this._parentSnackBar) {
this._parentSnackBar._openedSnackBarRef = value;
} else {
this._snackBarRefAtThisLevel = value;
}
}
constructor(
private _overlay: Overlay,
private _live: LiveAnnouncer,
@Optional() @SkipSelf() private _parentSnackBar: MdSnackBar) {}
/**
* Creates and dispatches a snack bar with a custom component for the content, removing any
@@ -50,18 +73,18 @@ export class MdSnackBar {
// When the snackbar is dismissed, clear the reference to it.
snackBarRef.afterDismissed().subscribe(() => {
// Clear the snackbar ref if it hasn't already been replaced by a newer snackbar.
if (this._snackBarRef == snackBarRef) {
this._snackBarRef = null;
if (this._openedSnackBarRef == snackBarRef) {
this._openedSnackBarRef = null;
}
});
// If a snack bar is already in view, dismiss it and enter the new snack bar after exit
// animation is complete.
if (this._snackBarRef) {
this._snackBarRef.afterDismissed().subscribe(() => {
if (this._openedSnackBarRef) {
this._openedSnackBarRef.afterDismissed().subscribe(() => {
snackBarRef.containerInstance.enter();
});
this._snackBarRef.dismiss();
this._openedSnackBarRef.dismiss();
// If no snack bar is in view, enter the new snack bar.
} else {
snackBarRef.containerInstance.enter();
@@ -75,8 +98,8 @@ export class MdSnackBar {
}
this._live.announce(config.announcementMessage, config.politeness);
this._snackBarRef = snackBarRef;
return this._snackBarRef;
this._openedSnackBarRef = snackBarRef;
return this._openedSnackBarRef;
}
/**
@@ -144,12 +167,14 @@ function _applyConfigDefaults(config: MdSnackBarConfig): MdSnackBarConfig {
exports: [MdSnackBarContainer, DefaultStyleCompatibilityModeModule],
declarations: [MdSnackBarContainer, SimpleSnackBar],
entryComponents: [MdSnackBarContainer, SimpleSnackBar],
providers: [MdSnackBar, LIVE_ANNOUNCER_PROVIDER]
})
export class MdSnackBarModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdSnackBarModule,
providers: [MdSnackBar, OVERLAY_PROVIDERS, LiveAnnouncer]
providers: []
};
}
}
+4 -2
View File
@@ -26,7 +26,7 @@ import {MdRippleModule} from '../core/ripple/ripple';
import {ObserveContentModule} from '../core/observe-content/observe-content';
import {MdTab} from './tab';
import {MdTabBody} from './tab-body';
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
import {VIEWPORT_RULER_PROVIDER} from '../core/overlay/position/viewport-ruler';
import {MdTabHeader} from './tab-header';
@@ -204,12 +204,14 @@ export class MdTabGroup {
exports: [MdTabGroup, MdTabLabel, MdTab, MdTabNavBar, MdTabLink, MdTabLinkRipple],
declarations: [MdTabGroup, MdTabLabel, MdTab, MdInkBar, MdTabLabelWrapper,
MdTabNavBar, MdTabLink, MdTabBody, MdTabLinkRipple, MdTabHeader],
providers: [VIEWPORT_RULER_PROVIDER],
})
export class MdTabsModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdTabsModule,
providers: [ViewportRuler]
providers: []
};
}
}
+1
View File
@@ -62,6 +62,7 @@ export class MdToolbar {
declarations: [MdToolbar, MdToolbarRow],
})
export class MdToolbarModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdToolbarModule,
+2 -2
View File
@@ -30,7 +30,6 @@ import {MdTooltipInvalidPositionError} from './tooltip-errors';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import {Dir} from '../core/rtl/dir';
import {OVERLAY_PROVIDERS} from '../core/overlay/overlay';
import 'rxjs/add/operator/first';
export type TooltipPosition = 'left' | 'right' | 'above' | 'below' | 'before' | 'after';
@@ -384,10 +383,11 @@ export class TooltipComponent {
entryComponents: [TooltipComponent],
})
export class MdTooltipModule {
/** @deprecated */
static forRoot(): ModuleWithProviders {
return {
ngModule: MdTooltipModule,
providers: [OVERLAY_PROVIDERS]
providers: []
};
}
}