refactor(core): remove deprecated @Component.directives and @Component.pipes

BREAKING CHANGE: previously deprecated @Component.directives and @Component.pipes support was removed.

All the components and pipes now must be declarated via an NgModule. NgModule is the basic
compilation block passed into the Angular compiler via Compiler#compileModuleSync or #compileModuleAsync.

Because of this change, the Compiler#compileComponentAsync and #compileComponentSync were removed as well -
any code doing compilation should compile module instead using the apis mentioned above.

Lastly, since modules are the basic compilation unit, the ngUpgrade module was modified to always require
an NgModule to be passed into the UpgradeAdapter's constructor - previously this was optional.
This commit is contained in:
Igor Minar 2016-08-19 13:51:45 -07:00
parent a782232ca3
commit 4a740f23a4
18 changed files with 389 additions and 665 deletions

View File

@ -410,7 +410,7 @@ export class CompileTemplateMetadata {
export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
static create(
{type, isComponent, selector, exportAs, changeDetection, inputs, outputs, host, providers,
viewProviders, queries, viewQueries, entryComponents, viewDirectives, viewPipes, template}: {
viewProviders, queries, viewQueries, entryComponents, template}: {
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string,
@ -479,8 +479,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
queries,
viewQueries,
entryComponents,
viewDirectives,
viewPipes,
template,
});
}
@ -500,17 +498,13 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
viewQueries: CompileQueryMetadata[];
// Note: Need to keep types here to prevent cycles!
entryComponents: CompileTypeMetadata[];
// Note: Need to keep types here to prevent cycles!
viewDirectives: CompileTypeMetadata[];
// Note: Need to keep types here to prevent cycles!
viewPipes: CompileTypeMetadata[];
template: CompileTemplateMetadata;
constructor(
{type, isComponent, selector, exportAs, changeDetection, inputs, outputs, hostListeners,
hostProperties, hostAttributes, providers, viewProviders, queries, viewQueries,
entryComponents, viewDirectives, viewPipes, template}: {
entryComponents, template}: {
type?: CompileTypeMetadata,
isComponent?: boolean,
selector?: string,
@ -547,8 +541,6 @@ export class CompileDirectiveMetadata implements CompileMetadataWithIdentifier {
this.queries = _normalizeArray(queries);
this.viewQueries = _normalizeArray(viewQueries);
this.entryComponents = _normalizeArray(entryComponents);
this.viewDirectives = _normalizeArray(viewDirectives);
this.viewPipes = _normalizeArray(viewPipes);
this.template = template;
}

View File

@ -142,8 +142,6 @@ export class DirectiveResolver {
providers: dm.providers,
viewProviders: dm.viewProviders,
entryComponents: dm.entryComponents,
directives: dm.directives,
pipes: dm.pipes,
template: dm.template,
templateUrl: dm.templateUrl,
styles: dm.styles,

View File

@ -8,12 +8,11 @@
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, AttributeMetadata, ChangeDetectionStrategy, ComponentMetadata, HostMetadata, InjectMetadata, Injectable, ModuleWithProviders, OptionalMetadata, Provider, QueryMetadata, SchemaMetadata, SelfMetadata, SkipSelfMetadata, Type, ViewQueryMetadata, resolveForwardRef} from '@angular/core';
import {Console, LIFECYCLE_HOOKS_VALUES, ReflectorReader, reflector} from '../core_private';
import {LIFECYCLE_HOOKS_VALUES, ReflectorReader, reflector} from '../core_private';
import {StringMapWrapper} from '../src/facade/collection';
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
import * as cpl from './compile_metadata';
import {CompilerConfig} from './config';
import {DirectiveResolver} from './directive_resolver';
import {BaseException} from './facade/exceptions';
import {isArray, isBlank, isPresent, isString, stringify} from './facade/lang';
@ -36,8 +35,7 @@ export class CompileMetadataResolver {
constructor(
private _ngModuleResolver: NgModuleResolver, private _directiveResolver: DirectiveResolver,
private _pipeResolver: PipeResolver, private _config: CompilerConfig,
private _console: Console, private _schemaRegistry: ElementSchemaRegistry,
private _pipeResolver: PipeResolver, private _schemaRegistry: ElementSchemaRegistry,
private _reflector: ReflectorReader = reflector) {}
private sanitizeTokenName(token: any): string {
@ -124,9 +122,7 @@ export class CompileMetadataResolver {
var changeDetectionStrategy: ChangeDetectionStrategy = null;
var viewProviders: Array<cpl.CompileProviderMetadata|cpl.CompileTypeMetadata|any[]> = [];
var moduleUrl = staticTypeModuleUrl(directiveType);
var viewDirectiveTypes: cpl.CompileTypeMetadata[] = [];
var viewPipeTypes: cpl.CompileTypeMetadata[] = [];
var entryComponentTypes: cpl.CompileTypeMetadata[] = [];
var entryComponentMetadata: cpl.CompileTypeMetadata[] = [];
let selector = dirMeta.selector;
if (dirMeta instanceof ComponentMetadata) {
var cmpMeta = <ComponentMetadata>dirMeta;
@ -150,32 +146,15 @@ export class CompileMetadataResolver {
changeDetectionStrategy = cmpMeta.changeDetection;
if (isPresent(dirMeta.viewProviders)) {
viewProviders = this.getProvidersMetadata(
verifyNonBlankProviders(directiveType, dirMeta.viewProviders, 'viewProviders'), []);
verifyNonBlankProviders(directiveType, dirMeta.viewProviders, 'viewProviders'),
entryComponentMetadata);
}
moduleUrl = componentModuleUrl(this._reflector, directiveType, cmpMeta);
if (cmpMeta.entryComponents) {
entryComponentTypes =
entryComponentMetadata =
flattenArray(cmpMeta.entryComponents)
.map((type) => this.getTypeMetadata(type, staticTypeModuleUrl(type)));
}
if (cmpMeta.directives) {
viewDirectiveTypes = flattenArray(cmpMeta.directives).map((type) => {
if (!type) {
throw new BaseException(
`Unexpected directive value '${type}' on the View of component '${stringify(directiveType)}'`);
}
return this.getTypeMetadata(type, staticTypeModuleUrl(type));
});
}
if (cmpMeta.pipes) {
viewPipeTypes = flattenArray(cmpMeta.pipes).map((type) => {
if (!type) {
throw new BaseException(
`Unexpected pipe value '${type}' on the View of component '${stringify(directiveType)}'`);
}
return this.getTypeMetadata(type, staticTypeModuleUrl(type));
});
.map((type) => this.getTypeMetadata(type, staticTypeModuleUrl(type)))
.concat(entryComponentMetadata);
}
if (!selector) {
selector = this._schemaRegistry.getDefaultComponentElementName();
@ -191,7 +170,7 @@ export class CompileMetadataResolver {
if (isPresent(dirMeta.providers)) {
providers = this.getProvidersMetadata(
verifyNonBlankProviders(directiveType, dirMeta.providers, 'providers'),
entryComponentTypes);
entryComponentMetadata);
}
var queries: cpl.CompileQueryMetadata[] = [];
var viewQueries: cpl.CompileQueryMetadata[] = [];
@ -213,9 +192,7 @@ export class CompileMetadataResolver {
viewProviders: viewProviders,
queries: queries,
viewQueries: viewQueries,
viewDirectives: viewDirectiveTypes,
viewPipes: viewPipeTypes,
entryComponents: entryComponentTypes
entryComponents: entryComponentMetadata
});
this._directiveCache.set(directiveType, meta);
}
@ -359,19 +336,6 @@ export class CompileMetadataResolver {
return compileMeta;
}
addComponentToModule(moduleType: Type<any>, compType: Type<any>) {
const moduleMeta = this.getNgModuleMetadata(moduleType);
// Collect @Component.directives/pipes/entryComponents into our declared directives/pipes.
const compMeta = this.getDirectiveMetadata(compType, false);
this._addDirectiveToModule(
compMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
moduleMeta.declaredDirectives);
moduleMeta.transitiveModule.entryComponents.push(compMeta.type);
moduleMeta.entryComponents.push(compMeta.type);
this._verifyModule(moduleMeta);
}
private _verifyModule(moduleMeta: cpl.CompileNgModuleMetadata) {
moduleMeta.exportedDirectives.forEach((dirMeta) => {
@ -386,17 +350,6 @@ export class CompileMetadataResolver {
`Can't export pipe ${stringify(pipeMeta.type.runtime)} from ${stringify(moduleMeta.type.runtime)} as it was neither declared nor imported!`);
}
});
moduleMeta.entryComponents.forEach((entryComponentType) => {
if (!moduleMeta.transitiveModule.directivesSet.has(entryComponentType.runtime)) {
throw new BaseException(
`NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(entryComponentType.runtime)} via "entryComponents" but it was neither declared nor imported! If ${stringify(entryComponentType.runtime)} is declared in an imported module, make sure it is exported.`);
}
});
// Collect @Component.directives/pipes/entryComponents into our declared
// directives/pipes. Do this last so that directives added by previous steps
// are considered as well!
moduleMeta.declaredDirectives.forEach(
(dirMeta) => { this._getTransitiveViewDirectivesAndPipes(dirMeta, moduleMeta); });
}
private _getTypeDescriptor(type: Type<any>): string {
@ -422,41 +375,6 @@ export class CompileMetadataResolver {
this._ngModuleOfTypes.set(type, moduleType);
}
private _getTransitiveViewDirectivesAndPipes(
compMeta: cpl.CompileDirectiveMetadata, moduleMeta: cpl.CompileNgModuleMetadata) {
if (!compMeta.isComponent) {
return;
}
const addPipe = (pipeType: Type<any>) => {
const pipeMeta = this.getPipeMetadata(pipeType);
this._addPipeToModule(
pipeMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule, moduleMeta.declaredPipes);
};
const addDirective = (dirType: Type<any>) => {
const dirMeta = this.getDirectiveMetadata(dirType);
if (this._addDirectiveToModule(
dirMeta, moduleMeta.type.runtime, moduleMeta.transitiveModule,
moduleMeta.declaredDirectives)) {
this._getTransitiveViewDirectivesAndPipes(dirMeta, moduleMeta);
}
};
if (compMeta.viewPipes) {
compMeta.viewPipes.forEach((cplType) => addPipe(cplType.runtime));
}
if (compMeta.viewDirectives) {
compMeta.viewDirectives.forEach((cplType) => addDirective(cplType.runtime));
}
compMeta.entryComponents.forEach((entryComponentType) => {
if (!moduleMeta.transitiveModule.directivesSet.has(entryComponentType.runtime)) {
this._console.warn(
`Component ${stringify(compMeta.type.runtime)} in NgModule ${stringify(moduleMeta.type.runtime)} uses ${stringify(entryComponentType.runtime)} via "entryComponents" but it was neither declared nor imported into the module! This warning will become an error after final.`);
addDirective(entryComponentType.runtime);
}
});
}
private _getTransitiveNgModuleMetadata(
importedModules: cpl.CompileNgModuleMetadata[],
exportedModules: cpl.CompileNgModuleMetadata[]): cpl.TransitiveCompileNgModuleMetadata {

View File

@ -46,8 +46,7 @@ export class RuntimeCompiler implements Compiler {
private _injector: Injector, private _metadataResolver: CompileMetadataResolver,
private _templateNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser,
private _styleCompiler: StyleCompiler, private _viewCompiler: ViewCompiler,
private _ngModuleCompiler: NgModuleCompiler, private _compilerConfig: CompilerConfig,
private _console: Console) {}
private _ngModuleCompiler: NgModuleCompiler, private _compilerConfig: CompilerConfig) {}
get injector(): Injector { return this._injector; }
@ -68,23 +67,6 @@ export class RuntimeCompiler implements Compiler {
return this._compileModuleAndAllComponents(moduleType, false).asyncResult;
}
compileComponentAsync<T>(compType: Type<T>, ngModule: Type<any> = null):
Promise<ComponentFactory<T>> {
if (!ngModule) {
throw new BaseException(
`Calling compileComponentAsync on the root compiler without a module is not allowed! (Compiling component ${stringify(compType)})`);
}
return this._compileComponentInModule(compType, false, ngModule).asyncResult;
}
compileComponentSync<T>(compType: Type<T>, ngModule: Type<any> = null): ComponentFactory<T> {
if (!ngModule) {
throw new BaseException(
`Calling compileComponentSync on the root compiler without a module is not allowed! (Compiling component ${stringify(compType)})`);
}
return this._compileComponentInModule(compType, true, ngModule).syncResult;
}
private _compileModuleAndComponents<T>(moduleType: Type<T>, isSync: boolean):
SyncAsyncResult<NgModuleFactory<T>> {
const componentPromise = this._compileComponents(moduleType, isSync);
@ -146,17 +128,6 @@ export class RuntimeCompiler implements Compiler {
return ngModuleFactory;
}
private _compileComponentInModule<T>(compType: Type<T>, isSync: boolean, moduleType: Type<any>):
SyncAsyncResult<ComponentFactory<T>> {
this._metadataResolver.addComponentToModule(moduleType, compType);
const componentPromise = this._compileComponents(moduleType, isSync);
const componentFactory: ComponentFactory<T> =
this._assertComponentKnown(compType, true).proxyComponentFactory;
return new SyncAsyncResult(componentFactory, componentPromise.then(() => componentFactory));
}
/**
* @internal
*/
@ -172,10 +143,13 @@ export class RuntimeCompiler implements Compiler {
dirMeta.entryComponents.forEach((entryComponentType) => {
templates.add(this._createCompiledHostTemplate(entryComponentType.runtime));
});
// TODO: what about entryComponents of entryComponents? maybe skip here and just do the
// below?
}
});
localModuleMeta.entryComponents.forEach((entryComponentType) => {
templates.add(this._createCompiledHostTemplate(entryComponentType.runtime));
// TODO: what about entryComponents of entryComponents?
});
});
templates.forEach((template) => {
@ -248,8 +222,13 @@ export class RuntimeCompiler implements Compiler {
const compiledTemplate = isHost ? this._compiledHostTemplateCache.get(compType) :
this._compiledTemplateCache.get(compType);
if (!compiledTemplate) {
throw new BaseException(
`Illegal state: CompiledTemplate for ${stringify(compType)} (isHost: ${isHost}) does not exist!`);
if (isHost) {
throw new BaseException(
`Illegal state: Compiled view for component ${stringify(compType)} does not exist!`);
} else {
throw new BaseException(
`Component ${stringify(compType)} is not part of any NgModule or the module has not been imported into your module.`);
}
}
return compiledTemplate;
}
@ -403,15 +382,6 @@ class ModuleBoundCompiler implements Compiler {
get _injector(): Injector { return this._delegate.injector; }
compileComponentAsync<T>(compType: Type<T>, ngModule: Type<any> = null):
Promise<ComponentFactory<T>> {
return this._delegate.compileComponentAsync(compType, ngModule ? ngModule : this._ngModule);
}
compileComponentSync<T>(compType: Type<T>, ngModule: Type<any> = null): ComponentFactory<T> {
return this._delegate.compileComponentSync(compType, ngModule ? ngModule : this._ngModule);
}
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> {
return this._delegate.compileModuleSync(moduleType);
}

View File

@ -6,17 +6,21 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Component, ComponentMetadata, Injector} from '@angular/core';
import {beforeEach, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
import {Component, ComponentMetadata, Directive, Injector} from '@angular/core';
import {TestBed, inject} from '@angular/core/testing';
import {ViewMetadata} from '../core_private';
import {isBlank, stringify} from '../src/facade/lang';
import {MockDirectiveResolver} from '../testing';
export function main() {
describe('MockDirectiveResolver', () => {
var dirResolver: MockDirectiveResolver;
beforeEach(() => {
TestBed.configureTestingModule(
{declarations: [SomeDirective, SomeOtherDirective, SomeComponent]});
});
beforeEach(inject([Injector], (injector: Injector) => {
dirResolver = new MockDirectiveResolver(injector);
}));
@ -40,14 +44,12 @@ export function main() {
it('should fallback to the default ViewResolver when templates are not overridden', () => {
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.template).toEqual('template');
expect(view.directives).toEqual([SomeDirective]);
});
it('should allow overriding the @View', () => {
dirResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.template).toEqual('overridden template');
expect(isBlank(view.directives)).toBe(true);
});
it('should allow overriding a view after it has been resolved', () => {
@ -55,7 +57,6 @@ export function main() {
dirResolver.setView(SomeComponent, new ViewMetadata({template: 'overridden template'}));
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.template).toEqual('overridden template');
expect(isBlank(view.directives)).toBe(true);
});
});
@ -64,7 +65,6 @@ export function main() {
dirResolver.setInlineTemplate(SomeComponent, 'overridden template');
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.template).toEqual('overridden template');
expect(view.directives).toEqual([SomeDirective]);
});
it('should allow overriding an overridden @View', () => {
@ -81,50 +81,17 @@ export function main() {
expect(view.template).toEqual('overridden template');
});
});
describe('Directive overriding', () => {
it('should allow overriding a directive from the default view', () => {
dirResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.directives.length).toEqual(1);
expect(view.directives[0]).toBe(SomeOtherDirective);
});
it('should allow overriding a directive from an overridden @View', () => {
dirResolver.setView(SomeComponent, new ViewMetadata({directives: [SomeOtherDirective]}));
dirResolver.overrideViewDirective(SomeComponent, SomeOtherDirective, SomeComponent);
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.directives.length).toEqual(1);
expect(view.directives[0]).toBe(SomeComponent);
});
it('should throw when the overridden directive is not present', () => {
dirResolver.overrideViewDirective(SomeComponent, SomeOtherDirective, SomeDirective);
expect(() => { dirResolver.resolve(SomeComponent); })
.toThrowError(
`Overriden directive ${stringify(SomeOtherDirective)} not found in the template of ${stringify(SomeComponent)}`);
});
it('should allow overriding a directive after its view has been resolved', () => {
dirResolver.resolve(SomeComponent);
dirResolver.overrideViewDirective(SomeComponent, SomeDirective, SomeOtherDirective);
var view = <ComponentMetadata>dirResolver.resolve(SomeComponent);
expect(view.directives.length).toEqual(1);
expect(view.directives[0]).toBe(SomeOtherDirective);
});
});
});
}
class SomeDirective {}
@Directive({selector: 'some-directive'})
class SomeDirective {
}
@Component({
selector: 'cmp',
template: 'template',
directives: [SomeDirective],
})
@Component({selector: 'cmp', template: 'template'})
class SomeComponent {
}
class SomeOtherDirective {}
@Directive({selector: 'some-other-directive'})
class SomeOtherDirective {
}

View File

@ -104,16 +104,7 @@ class SomeDirectiveWithViewChild {
c: any;
}
class SomeDir {}
class SomePipe {}
@Component({
selector: 'sample',
template: 'some template',
directives: [SomeDir],
pipes: [SomePipe],
styles: ['some styles']
})
@Component({selector: 'sample', template: 'some template', styles: ['some styles']})
class ComponentWithTemplate {
}
@ -236,8 +227,6 @@ export function main() {
it('should read out the template related metadata from the Component metadata', () => {
var compMetadata = <ComponentMetadata>resolver.resolve(ComponentWithTemplate);
expect(compMetadata.template).toEqual('some template');
expect(compMetadata.directives).toEqual([SomeDir]);
expect(compMetadata.pipes).toEqual([SomePipe]);
expect(compMetadata.styles).toEqual(['some styles']);
});
});

View File

@ -140,12 +140,12 @@ export function main() {
it('should throw when using a templateUrl in a nested component that has not been compiled before',
() => {
@NgModule({declarations: [SomeComp], entryComponents: [SomeComp]})
@NgModule({declarations: [SomeComp, ChildComp], entryComponents: [SomeComp]})
class SomeModule {
}
resourceLoader.spy('get').andCallFake(() => Promise.resolve(''));
dirResolver.setView(SomeComp, new ViewMetadata({template: '', directives: [ChildComp]}));
dirResolver.setView(SomeComp, new ViewMetadata({template: ''}));
dirResolver.setView(ChildComp, new ViewMetadata({templateUrl: '/someTpl.html'}));
expect(() => compiler.compileModuleSync(SomeModule))
.toThrowError(

View File

@ -7,7 +7,6 @@
*/
export * from './testing/schema_registry_mock';
export * from './testing/test_component_builder';
export * from './testing/directive_resolver_mock';
export * from './testing/ng_module_resolver_mock';
export * from './testing/pipe_resolver_mock';
@ -39,13 +38,7 @@ export class TestingCompilerImpl implements TestingCompiler {
private _compiler: RuntimeCompiler, private _directiveResolver: MockDirectiveResolver,
private _pipeResolver: MockPipeResolver, private _moduleResolver: MockNgModuleResolver) {}
get injector(): Injector { return this._compiler.injector; }
compileComponentAsync<T>(component: Type<T>, ngModule: Type<any> = null):
Promise<ComponentFactory<T>> {
return this._compiler.compileComponentAsync(component, <any>ngModule);
}
compileComponentSync<T>(component: Type<T>, ngModule: Type<any> = null): ComponentFactory<T> {
return this._compiler.compileComponentSync(component, <any>ngModule);
}
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T> {
return this._compiler.compileModuleSync(moduleType);
}

View File

@ -11,8 +11,7 @@ import {ViewMetadata} from '../core_private';
import {DirectiveResolver} from '../src/directive_resolver';
import {Map} from '../src/facade/collection';
import {BaseException} from '../src/facade/exceptions';
import {isArray, isPresent, stringify} from '../src/facade/lang';
import {isArray, isPresent} from '../src/facade/lang';
@ -28,7 +27,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
private _views = new Map<Type<any>, ViewMetadata>();
private _inlineTemplates = new Map<Type<any>, string>();
private _animations = new Map<Type<any>, AnimationEntryMetadata[]>();
private _directiveOverrides = new Map<Type<any>, Map<Type<any>, Type<any>>>();
constructor(private _injector: Injector) { super(); }
@ -67,13 +65,8 @@ export class MockDirectiveResolver extends DirectiveResolver {
view = metadata;
}
const directives: any[] = [];
if (isPresent(view.directives)) {
flattenArray(view.directives, directives);
}
let animations = view.animations;
let templateUrl = view.templateUrl;
const directiveOverrides = this._directiveOverrides.get(type);
const inlineAnimations = this._animations.get(type);
if (isPresent(inlineAnimations)) {
@ -87,17 +80,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
inlineTemplate = view.template;
}
if (isPresent(directiveOverrides) && isPresent(view.directives)) {
directiveOverrides.forEach((to, from) => {
var srcIndex = directives.indexOf(from);
if (srcIndex == -1) {
throw new BaseException(
`Overriden directive ${stringify(from)} not found in the template of ${stringify(type)}`);
}
directives[srcIndex] = to;
});
}
return new ComponentMetadata({
selector: metadata.selector,
inputs: metadata.inputs,
@ -112,11 +94,9 @@ export class MockDirectiveResolver extends DirectiveResolver {
entryComponents: metadata.entryComponents,
template: inlineTemplate,
templateUrl: templateUrl,
directives: directives.length > 0 ? directives : null,
animations: animations,
styles: view.styles,
styleUrls: view.styleUrls,
pipes: view.pipes,
encapsulation: view.encapsulation,
interpolation: view.interpolation
});
@ -170,21 +150,6 @@ export class MockDirectiveResolver extends DirectiveResolver {
this._animations.set(component, animations);
this._clearCacheFor(component);
}
/**
* Overrides a directive from the component {@link ViewMetadata}.
*/
overrideViewDirective(component: Type<any>, from: Type<any>, to: Type<any>): void {
var overrides = this._directiveOverrides.get(component);
if (!overrides) {
overrides = new Map<Type<any>, Type<any>>();
this._directiveOverrides.set(component, overrides);
}
overrides.set(from, to);
this._clearCacheFor(component);
}
}
function flattenArray(tree: any[], out: Array<Type<any>|any[]>): void {

View File

@ -304,11 +304,23 @@ export class PlatformRef_ extends PlatformRef {
}
private _bootstrapModuleWithZone<M>(
moduleType: Type<M>, compilerOptions: CompilerOptions|CompilerOptions[] = [],
ngZone: NgZone): Promise<NgModuleRef<M>> {
moduleType: Type<M>, compilerOptions: CompilerOptions|CompilerOptions[] = [], ngZone: NgZone,
componentFactoryCallback?: any): Promise<NgModuleRef<M>> {
const compilerFactory: CompilerFactory = this.injector.get(CompilerFactory);
const compiler = compilerFactory.createCompiler(
compilerOptions instanceof Array ? compilerOptions : [compilerOptions]);
// ugly internal api hack: generate host component factories for all declared components and
// pass the factories into the callback - this is used by UpdateAdapter to get hold of all
// factories.
if (componentFactoryCallback) {
return compiler.compileModuleAndAllComponentsAsync(moduleType)
.then(({ngModuleFactory, componentFactories}) => {
componentFactoryCallback(componentFactories);
return this._bootstrapModuleFactoryWithZone(ngModuleFactory, ngZone);
});
}
return compiler.compileModuleAsync(moduleType)
.then((moduleFactory) => this._bootstrapModuleFactoryWithZone(moduleFactory, ngZone));
}

View File

@ -45,7 +45,7 @@ function _throwError() {
}
/**
* Low-level service for running the angular compiler duirng runtime
* Low-level service for running the angular compiler during runtime
* to create {@link ComponentFactory}s, which
* can later be used to create and render a Component instance.
*
@ -55,20 +55,6 @@ function _throwError() {
* @stable
*/
export class Compiler {
/**
* Loads the template and styles of a component and returns the associated `ComponentFactory`.
*/
compileComponentAsync<T>(component: Type<T>, ngModule: Type<any> = null):
Promise<ComponentFactory<T>> {
throw _throwError();
}
/**
* Compiles the given component. All templates have to be either inline or compiled via
* `compileComponentAsync` before. Otherwise throws a {@link ComponentStillLoadingError}.
*/
compileComponentSync<T>(component: Type<T>, ngModule: Type<any> = null): ComponentFactory<T> {
throw _throwError();
}
/**
* Compiles the given NgModule and all of its components. All templates of the components listed
* in `entryComponents`

View File

@ -481,8 +481,7 @@ export class DirectiveMetadata extends InjectableMetadata implements DirectiveMe
* selector: 'app',
* template: `
* <bank-account bank-name="RBC" account-id="4747"></bank-account>
* `,
* directives: [BankAccount]
* `
* })
* class App {}
* ```
@ -525,8 +524,7 @@ export class DirectiveMetadata extends InjectableMetadata implements DirectiveMe
* template: `
* <interval-dir (everySecond)="everySecond()" (everyFiveSeconds)="everyFiveSeconds()">
* </interval-dir>
* `,
* directives: [IntervalDir]
* `
* })
* class App {
* everySecond() { console.log('second'); }
@ -578,8 +576,7 @@ export class DirectiveMetadata extends InjectableMetadata implements DirectiveMe
*
* @Component({
* selector: 'app',
* template: `<button counting>Increment</button>`,
* directives: [CountClicks]
* template: `<button counting>Increment</button>`
* })
* class App {}
* ```
@ -612,8 +609,7 @@ export class DirectiveMetadata extends InjectableMetadata implements DirectiveMe
*
* @Component({
* selector: 'app',
* template: `<input [(ngModel)]="prop">`,
* directives: [FORM_DIRECTIVES, NgModelStatus]
* template: `<input [(ngModel)]="prop">`
* })
* class App {
* prop;
@ -690,8 +686,7 @@ export class DirectiveMetadata extends InjectableMetadata implements DirectiveMe
*
* @Component({
* selector: 'main',
* template: `<child-dir #c="child"></child-dir>`,
* directives: [ChildDir]
* template: `<child-dir #c="child"></child-dir>`
* })
* class MainComponent {
* }
@ -716,8 +711,7 @@ export class DirectiveMetadata extends InjectableMetadata implements DirectiveMe
* contentChildren: new ContentChildren(ChildDirective),
* viewChildren: new ViewChildren(ChildDirective)
* },
* template: '<child-directive></child-directive>',
* directives: [ChildDirective]
* template: '<child-directive></child-directive>'
* })
* class SomeDir {
* contentChildren: QueryList<ChildDirective>,
@ -761,8 +755,6 @@ export interface ComponentMetadataType extends DirectiveMetadataType {
styleUrls?: string[];
styles?: string[];
animations?: AnimationEntryMetadata[];
directives?: Array<Type<any>|any[]>;
pipes?: Array<Type<any>|any[]>;
encapsulation?: ViewEncapsulation;
interpolation?: [string, string];
entryComponents?: Array<Type<any>|any[]>;
@ -836,8 +828,7 @@ export class ComponentMetadata extends DirectiveMetadata implements ComponentMet
* viewProviders: [
* Greeter
* ],
* template: `<needs-greeter></needs-greeter>`,
* directives: [NeedsGreeter]
* template: `<needs-greeter></needs-greeter>`
* })
* class HelloWorld {
* }
@ -969,10 +960,6 @@ export class ComponentMetadata extends DirectiveMetadata implements ComponentMet
*/
animations: AnimationEntryMetadata[];
directives: Array<Type<any>|any[]>;
pipes: Array<Type<any>|any[]>;
/**
* Specify how the template and the styles should be encapsulated.
* The default is {@link ViewEncapsulation#Emulated `ViewEncapsulation.Emulated`} if the view
@ -991,13 +978,11 @@ export class ComponentMetadata extends DirectiveMetadata implements ComponentMet
*/
entryComponents: Array<Type<any>|any[]>;
constructor({selector, inputs, outputs,
host, exportAs, moduleId,
providers, viewProviders, changeDetection = ChangeDetectionStrategy.Default,
queries, templateUrl, template,
styleUrls, styles, animations,
directives, pipes, encapsulation,
interpolation, entryComponents}: ComponentMetadataType = {}) {
constructor(
{selector, inputs, outputs, host, exportAs, moduleId, providers, viewProviders,
changeDetection = ChangeDetectionStrategy.Default, queries, templateUrl, template, styleUrls,
styles, animations, encapsulation, interpolation,
entryComponents}: ComponentMetadataType = {}) {
super({
selector: selector,
inputs: inputs,
@ -1014,8 +999,6 @@ export class ComponentMetadata extends DirectiveMetadata implements ComponentMet
this.template = template;
this.styleUrls = styleUrls;
this.styles = styles;
this.directives = directives;
this.pipes = pipes;
this.encapsulation = encapsulation;
this.moduleId = moduleId;
this.animations = animations;
@ -1092,9 +1075,9 @@ export class PipeMetadata extends InjectableMetadata implements PipeMetadataType
* selector: 'app',
* template: `
* <bank-account bank-name="RBC" account-id="4747"></bank-account>
* `,
* directives: [BankAccount]
* `
* })
*
* class App {}
* ```
* @stable
@ -1138,8 +1121,7 @@ export class InputMetadata {
* template: `
* <interval-dir (everySecond)="everySecond()" (everyFiveSeconds)="everyFiveSeconds()">
* </interval-dir>
* `,
* directives: [IntervalDir]
* `
* })
* class App {
* everySecond() { console.log('second'); }
@ -1177,8 +1159,7 @@ export class OutputMetadata {
*
* @Component({
* selector: 'app',
* template: `<input [(ngModel)]="prop">`,
* directives: [FORM_DIRECTIVES, NgModelStatus]
* template: `<input [(ngModel)]="prop">`
* })
* class App {
* prop;
@ -1216,8 +1197,7 @@ export class HostBindingMetadata {
*
* @Component({
* selector: 'app',
* template: `<button counting>Increment</button>`,
* directives: [CountClicks]
* template: `<button counting>Increment</button>`
* })
* class App {}
* ```

View File

@ -103,30 +103,6 @@ export class ViewMetadata {
*/
styles: string[];
/**
* Specifies a list of directives that can be used within a template.
*
* Directives must be listed explicitly to provide proper component encapsulation.
*
* ### Example
*
* ```javascript
* @Component({
* selector: 'my-component',
* directives: [NgFor]
* template: '
* <ul>
* <li *ngFor="let item of items">{{item}}</li>
* </ul>'
* })
* class MyComponent {
* }
* ```
*/
directives: Array<Type<any>|any[]>;
pipes: Array<Type<any>|any[]>;
/**
* Specify how the template and the styles should be encapsulated.
* The default is {@link ViewEncapsulation#Emulated `ViewEncapsulation.Emulated`} if the view
@ -140,12 +116,9 @@ export class ViewMetadata {
interpolation: [string, string];
constructor(
{templateUrl, template, directives, pipes, encapsulation, styles, styleUrls, animations,
interpolation}: {
{templateUrl, template, encapsulation, styles, styleUrls, animations, interpolation}: {
templateUrl?: string,
template?: string,
directives?: Array<Type<any>|any[]>,
pipes?: Array<Type<any>|any[]>,
encapsulation?: ViewEncapsulation,
styles?: string[],
styleUrls?: string[],
@ -156,8 +129,6 @@ export class ViewMetadata {
this.template = template;
this.styleUrls = styleUrls;
this.styles = styles;
this.directives = directives;
this.pipes = pipes;
this.encapsulation = encapsulation;
this.animations = animations;
this.interpolation = interpolation;

View File

@ -8,8 +8,7 @@
import {ANALYZE_FOR_ENTRY_COMPONENTS, CUSTOM_ELEMENTS_SCHEMA, Compiler, Component, ComponentFactoryResolver, Directive, HostBinding, Inject, Injectable, Injector, Input, NgModule, NgModuleRef, Optional, Pipe, SelfMetadata, Type, forwardRef} from '@angular/core';
import {Console} from '@angular/core/src/console';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {AsyncTestCompleter, beforeEach, beforeEachProviders, ddescribe, describe, iit, inject, it, xdescribe, xit} from '@angular/core/testing/testing_internal';
import {ComponentFixture, TestBed, inject} from '@angular/core/testing';
import {expect} from '@angular/platform-browser/testing/matchers';
import {BaseException} from '../../src/facade/exceptions';
@ -263,20 +262,35 @@ function declareTests({useJit}: {useJit: boolean}) {
.toBe(SomeComp);
});
it('should throw when using an entryComponent that was neither declared nor imported', () => {
@Component({template: '', entryComponents: [SomeComp]})
it('should throw if we cannot find a module associated with a module-level entryComponent', () => {
@Component({template: ''})
class SomeCompWithEntryComponents {
}
@NgModule({entryComponents: [SomeCompWithEntryComponents]})
@NgModule({declarations: [], entryComponents: [SomeCompWithEntryComponents]})
class SomeModule {
}
expect(() => createModule(SomeModule))
.toThrowError(
`NgModule ${stringify(SomeModule)} uses ${stringify(SomeCompWithEntryComponents)} via "entryComponents" but it was neither declared nor imported! If ${stringify(SomeCompWithEntryComponents)} is declared in an imported module, make sure it is exported.`);
'Component SomeCompWithEntryComponents is not part of any NgModule or the module has not been imported into your module.');
});
it('should throw if we cannot find a module associated with a component-level entryComponent',
() => {
@Component({template: '', entryComponents: [SomeComp]})
class SomeCompWithEntryComponents {
}
@NgModule({declarations: [SomeCompWithEntryComponents]})
class SomeModule {
}
expect(() => createModule(SomeModule))
.toThrowError(
'Component SomeComp is not part of any NgModule or the module has not been imported into your module.');
});
it('should create ComponentFactories via ANALYZE_FOR_ENTRY_COMPONENTS', () => {
@NgModule({
declarations: [SomeComp],
@ -417,61 +431,6 @@ function declareTests({useJit}: {useJit: boolean}) {
expect(compFixture.debugElement.children[0].children[0].properties['title'])
.toBe('transformed someValue');
});
it('should hoist @Component.directives/pipes into the module', () => {
@Component({
selector: 'parent',
template: '<comp></comp>',
directives: [CompUsingModuleDirectiveAndPipe, SomeDirective],
pipes: [SomePipe]
})
class ParentCompUsingModuleDirectiveAndPipe {
}
@NgModule({
declarations: [ParentCompUsingModuleDirectiveAndPipe],
entryComponents: [ParentCompUsingModuleDirectiveAndPipe]
})
class SomeModule {
}
const compFixture = createComp(ParentCompUsingModuleDirectiveAndPipe, SomeModule);
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].children[0].properties['title'])
.toBe('transformed someValue');
});
it('should allow to use directives/pipes via @Component.directives/pipes that were already imported from another module',
() => {
@Component({
selector: 'parent',
template: '<comp></comp>',
directives: [CompUsingModuleDirectiveAndPipe, SomeDirective],
pipes: [SomePipe]
})
class ParentCompUsingModuleDirectiveAndPipe {
}
@NgModule({
declarations: [SomeDirective, SomePipe, CompUsingModuleDirectiveAndPipe],
exports: [SomeDirective, SomePipe, CompUsingModuleDirectiveAndPipe]
})
class SomeImportedModule {
}
@NgModule({
declarations: [ParentCompUsingModuleDirectiveAndPipe],
imports: [SomeImportedModule],
entryComponents: [ParentCompUsingModuleDirectiveAndPipe]
})
class SomeModule {
}
const compFixture = createComp(ParentCompUsingModuleDirectiveAndPipe, SomeModule);
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].children[0].properties['title'])
.toBe('transformed someValue');
});
});
describe('import/export', () => {
@ -603,24 +562,6 @@ function declareTests({useJit}: {useJit: boolean}) {
});
});
describe('bound compiler', () => {
it('should provide a Compiler instance that uses the directives/pipes of the module', () => {
@NgModule({declarations: [SomeDirective, SomePipe]})
class SomeModule {
}
const ngModule = createModule(SomeModule);
const boundCompiler: Compiler = ngModule.injector.get(Compiler);
const cf = boundCompiler.compileComponentSync(CompUsingModuleDirectiveAndPipe);
const compFixture = new ComponentFixture(cf.create(injector), null, false);
compFixture.detectChanges();
expect(compFixture.debugElement.children[0].properties['title'])
.toBe('transformed someValue');
// compile again should produce the same result
expect(boundCompiler.compileComponentSync(CompUsingModuleDirectiveAndPipe)).toBe(cf);
});
});
describe('providers', function() {
let moduleType: any = null;

View File

@ -6,8 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BaseException, Compiler, ComponentFactory, Injector, NgModule, NgModuleRef, NgZone, Provider, Testability, Type} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {BaseException, Compiler, ComponentFactory, ComponentFactoryResolver, Injector, NgModule, NgModuleRef, NgZone, Provider, Testability, Type} from '@angular/core';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import * as angular from './angular_js';
@ -117,10 +116,10 @@ export class UpgradeAdapter {
// the ng2AppModule param should be required once the deprecated @Component.directives prop is
// removed
constructor(private ng2AppModule?: Type<any>) {
if (arguments.length && !ng2AppModule) {
constructor(private ng2AppModule: Type<any>) {
if (!ng2AppModule) {
throw new BaseException(
'UpgradeAdapter constructor called with undefined instead of a ng module type');
'UpgradeAdapter cannot be instantiated without an NgModule of the Angular 2 app.');
}
}
@ -394,10 +393,21 @@ export class UpgradeAdapter {
{provide: NG1_COMPILE, useFactory: () => ng1Injector.get(NG1_COMPILE)},
this.providers
],
imports: this.ng2AppModule ? [this.ng2AppModule] : [BrowserModule]
}).Class({constructor: function() {}, ngDoBootstrap: function() {}});
imports: [this.ng2AppModule]
}).Class({
constructor: function DynamicNgUpgradeModule() {},
ngDoBootstrap: function() {}
});
(platformBrowserDynamic() as any)
._bootstrapModuleWithZone(DynamicNgUpgradeModule, undefined, ngZone)
._bootstrapModuleWithZone(
DynamicNgUpgradeModule, undefined, ngZone,
(componentFactories: ComponentFactory<any>[]) => {
componentFactories.forEach((componentFactory) => {
componentFactoryRefMap[getComponentInfo(componentFactory.componentType)
.selector] = componentFactory;
});
})
.then((ref: NgModuleRef<any>) => {
moduleRef = ref;
angular.element(element).data(
@ -417,7 +427,7 @@ export class UpgradeAdapter {
windowAngular.resumeBootstrap = undefined;
ngZone.run(() => { angular.bootstrap(element, [this.idPrefix], config); });
ng1BootstrapPromise = new Promise((resolve, reject) => {
ng1BootstrapPromise = new Promise((resolve) => {
if (windowAngular.resumeBootstrap) {
var originalResumeBootstrap: () => void = windowAngular.resumeBootstrap;
windowAngular.resumeBootstrap = function() {
@ -430,23 +440,18 @@ export class UpgradeAdapter {
}
});
Promise.all([ng1BootstrapPromise, ng1compilePromise])
.then(() => {
return this.compileNg2Components(
moduleRef.injector.get(Compiler), componentFactoryRefMap);
})
.then(() => {
moduleRef.injector.get(NgZone).run(() => {
if (rootScopePrototype) {
rootScopePrototype.$apply = original$applyFn; // restore original $apply
while (delayApplyExps.length) {
rootScope.$apply(delayApplyExps.shift());
}
(<any>upgrade)._bootstrapDone(moduleRef, ng1Injector);
rootScopePrototype = null;
}
});
}, onError);
Promise.all([ng1BootstrapPromise, ng1compilePromise]).then(() => {
moduleRef.injector.get(NgZone).run(() => {
if (rootScopePrototype) {
rootScopePrototype.$apply = original$applyFn; // restore original $apply
while (delayApplyExps.length) {
rootScope.$apply(delayApplyExps.shift());
}
(<any>upgrade)._bootstrapDone(moduleRef, ng1Injector);
rootScopePrototype = null;
}
});
}, onError);
return upgrade;
}
@ -518,23 +523,6 @@ export class UpgradeAdapter {
(<any>factory).$inject = [NG2_INJECTOR];
return factory;
}
/* @internal */
private compileNg2Components(compiler: Compiler, componentFactoryRefMap: ComponentFactoryRefMap):
Promise<ComponentFactoryRefMap> {
var promises: Array<Promise<ComponentFactory<any>>> = [];
var types = this.upgradedComponents;
for (var i = 0; i < types.length; i++) {
promises.push(compiler.compileComponentAsync(<any>types[i], this.ng2AppModule));
}
return Promise.all(promises).then((componentFactories: Array<ComponentFactory<any>>) => {
var types = this.upgradedComponents;
for (var i = 0; i < componentFactories.length; i++) {
componentFactoryRefMap[getComponentInfo(types[i]).selector] = componentFactories[i];
}
return componentFactoryRefMap;
}, onError);
}
}
interface ComponentFactoryRefMap {

View File

@ -6,9 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Class, Component, EventEmitter, Inject, NgModule, OpaqueToken, Testability, destroyPlatform} from '@angular/core';
import {Class, Component, EventEmitter, Inject, NgModule, OpaqueToken, Testability, destroyPlatform, forwardRef} from '@angular/core';
import {async} from '@angular/core/testing';
import {AsyncTestCompleter, ddescribe, describe, expect, iit, inject, it} from '@angular/core/testing/testing_internal';
import {BrowserModule} from '@angular/platform-browser';
import {UpgradeAdapter} from '@angular/upgrade';
import * as angular from '@angular/upgrade/src/angular_js';
@ -20,34 +19,40 @@ export function main() {
it('should have angular 1 loaded', () => expect(angular.version.major).toBe(1));
it('should instantiate ng2 in ng1 template and project content',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
it('should instantiate ng2 in ng1 template and project content', async(() => {
var ng1Module = angular.module('ng1', []);
var Ng2 = Component({selector: 'ng2', template: `{{ 'NG2' }}(<ng-content></ng-content>)`})
.Class({constructor: function() {}});
var Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({
constructor: function() {}
});
var element =
html('<div>{{ \'ng1[\' }}<ng2>~{{ \'ng-content\' }}~</ng2>{{ \']\' }}</div>');
var adapter: UpgradeAdapter = new UpgradeAdapter();
const adapter: UpgradeAdapter = new UpgradeAdapter(Ng2Module);
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(document.body.textContent).toEqual('ng1[NG2(~ng-content~)]');
ref.dispose();
async.done();
});
}));
it('should instantiate ng1 in ng2 template and project content',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter: UpgradeAdapter = new UpgradeAdapter();
it('should instantiate ng1 in ng2 template and project content', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var Ng2 = Component({
selector: 'ng2',
template: `{{ 'ng2(' }}<ng1>{{'transclude'}}</ng1>{{ ')' }}`,
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
}).Class({constructor: function Ng2() {}});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function Ng2Module() {}});
ng1Module.directive('ng1', () => {
return {transclude: true, template: '{{ "ng1" }}(<ng-transclude></ng-transclude>)'};
@ -59,19 +64,17 @@ export function main() {
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(document.body.textContent).toEqual('ng1(ng2(ng1(transclude)))');
ref.dispose();
async.done();
});
}));
describe('scope/component change-detection', () => {
it('should interleave scope and component expressions',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
it('should interleave scope and component expressions', async(() => {
var ng1Module = angular.module('ng1', []);
var log: any[] /** TODO #9100 */ = [];
var l = function(value: any /** TODO #9100 */) {
log.push(value);
return value + ';';
};
var adapter: UpgradeAdapter = new UpgradeAdapter();
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
ng1Module.directive('ng1a', () => { return {template: '{{ l(\'ng1a\') }}'}; });
ng1Module.directive('ng1b', () => { return {template: '{{ l(\'ng1b\') }}'}; });
@ -80,13 +83,18 @@ export function main() {
$rootScope.reset = () => log.length = 0;
});
var Ng2 =
Component({
selector: 'ng2',
template: `{{l('2A')}}<ng1a></ng1a>{{l('2B')}}<ng1b></ng1b>{{l('2C')}}`,
directives:
[adapter.upgradeNg1Component('ng1a'), adapter.upgradeNg1Component('ng1b')]
}).Class({constructor: function() { this.l = l; }});
var Ng2 = Component({
selector: 'ng2',
template: `{{l('2A')}}<ng1a></ng1a>{{l('2B')}}<ng1b></ng1b>{{l('2C')}}`
}).Class({constructor: function() { this.l = l; }});
var Ng2Module =
NgModule({
declarations: [
adapter.upgradeNg1Component('ng1a'), adapter.upgradeNg1Component('ng1b'), Ng2
],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
@ -97,15 +105,13 @@ export function main() {
// https://github.com/angular/angular.js/issues/12983
expect(log).toEqual(['1A', '1B', '1C', '2A', '2B', '2C', 'ng1a', 'ng1b']);
ref.dispose();
async.done();
});
}));
});
describe('downgrade ng2 component', () => {
it('should bind properties, events',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter: UpgradeAdapter = new UpgradeAdapter();
it('should bind properties, events', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
ng1Module.run(($rootScope: any /** TODO #9100 */) => {
@ -189,6 +195,11 @@ export function main() {
}
});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({
constructor: function() {}
});
var element = html(`<div>
<ng2 literal="Text" interpolate="Hello {{'world'}}"
bind-one-way-a="dataA" [one-way-b]="dataB"
@ -204,14 +215,12 @@ export function main() {
'oneWayA: A; oneWayB: B; twoWayA: newA; twoWayB: newB; (2) | ' +
'modelA: newA; modelB: newB; eventA: aFired; eventB: bFired;');
ref.dispose();
async.done();
});
}));
it('should properly run cleanup when ng1 directive is destroyed',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter: UpgradeAdapter = new UpgradeAdapter();
it('should properly run cleanup when ng1 directive is destroyed', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var onDestroyed: EventEmitter<string> = new EventEmitter<string>();
@ -229,20 +238,21 @@ export function main() {
constructor: function() {},
ngOnDestroy: function() { onDestroyed.emit('destroyed'); }
});
var Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({
constructor: function() {}
});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html('<ng1></ng1>');
adapter.bootstrap(element, ['ng1']).ready((ref) => {
onDestroyed.subscribe(() => {
ref.dispose();
async.done();
});
onDestroyed.subscribe(() => { ref.dispose(); });
});
}));
it('should fallback to the root ng2.injector when compiled outside the dom',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter: UpgradeAdapter = new UpgradeAdapter();
it('should fallback to the root ng2.injector when compiled outside the dom', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
ng1Module.directive('ng1', [
@ -262,12 +272,16 @@ export function main() {
var Ng2 =
Component({selector: 'ng2', template: 'test'}).Class({constructor: function() {}});
var Ng2Module = NgModule({declarations: [Ng2], imports: [BrowserModule]}).Class({
constructor: function() {}
});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html('<ng1></ng1>');
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('test');
ref.dispose();
async.done();
});
}));
@ -308,9 +322,8 @@ export function main() {
});
describe('upgrade ng1 component', () => {
it('should bind properties, events',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should bind properties, events', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() {
@ -338,8 +351,7 @@ export function main() {
'<ng1 fullName="{{last}}, {{first}}" [modelA]="first" [(modelB)]="last" ' +
'(event)="event=$event"></ng1>' +
'<ng1 fullName="{{\'TEST\'}}" modelA="First" modelB="Last"></ng1>' +
'{{event}}-{{last}}, {{first}}',
directives: [adapter.upgradeNg1Component('ng1')]
'{{event}}-{{last}}, {{first}}'
}).Class({
constructor: function() {
this.first = 'Victor';
@ -347,6 +359,12 @@ export function main() {
this.event = '?';
}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
@ -357,14 +375,13 @@ export function main() {
.toEqual(
'Hello SAVKIN, Victor; A: VICTOR; B: SAVKIN; | Hello TEST; A: First; B: Last; | WORKS-SAVKIN, Victor');
ref.dispose();
async.done();
}, 0);
});
}));
it('should bind properties, events in controller when bindToController is not used',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() {
@ -383,8 +400,7 @@ export function main() {
Component({
selector: 'ng2',
template:
'{{someText}} - Length: {{dataList.length}} | <ng1 [(data)]="dataList"></ng1>',
directives: [adapter.upgradeNg1Component('ng1')],
'{{someText}} - Length: {{dataList.length}} | <ng1 [(data)]="dataList"></ng1>'
}).Class({
constructor: function() {
@ -392,6 +408,12 @@ export function main() {
this.someText = 'ng2';
}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
@ -401,14 +423,12 @@ export function main() {
expect(multiTrim(document.body.textContent))
.toEqual('ng2 - Length: 3 | ng1 - Data: 1,2,3 - Length: 3');
ref.dispose();
async.done();
}, 0);
});
}));
it('should bind properties, events in link function',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should bind properties, events in link function', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() {
@ -427,8 +447,7 @@ export function main() {
Component({
selector: 'ng2',
template:
'{{someText}} - Length: {{dataList.length}} | <ng1 [(data)]="dataList"></ng1>',
directives: [adapter.upgradeNg1Component('ng1')],
'{{someText}} - Length: {{dataList.length}} | <ng1 [(data)]="dataList"></ng1>'
}).Class({
constructor: function() {
@ -436,6 +455,12 @@ export function main() {
this.someText = 'ng2';
}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
@ -445,14 +470,12 @@ export function main() {
expect(multiTrim(document.body.textContent))
.toEqual('ng2 - Length: 3 | ng1 - Data: 1,2,3 - Length: 3');
ref.dispose();
async.done();
}, 0);
});
}));
it('should support templateUrl fetched from $httpBackend',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support templateUrl fetched from $httpBackend', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
ng1Module.value(
'$httpBackend', (method: any /** TODO #9100 */, url: any /** TODO #9100 */,
@ -461,23 +484,25 @@ export function main() {
var ng1 = function() { return {templateUrl: 'url.html'}; };
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('GET:url.html');
ref.dispose();
async.done();
});
}));
it('should support templateUrl as a function',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support templateUrl as a function', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
ng1Module.value(
'$httpBackend', (method: any /** TODO #9100 */, url: any /** TODO #9100 */,
@ -486,88 +511,100 @@ export function main() {
var ng1 = function() { return {templateUrl() { return 'url.html'; }}; };
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('GET:url.html');
ref.dispose();
async.done();
});
}));
it('should support empty template',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support empty template', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() { return {template: ''}; };
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('');
ref.dispose();
async.done();
});
}));
it('should support template as a function',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support template as a function', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() { return {template() { return ''; }}; };
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('');
ref.dispose();
async.done();
});
}));
it('should support templateUrl fetched from $templateCache',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support templateUrl fetched from $templateCache', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
ng1Module.run(
($templateCache: any /** TODO #9100 */) => $templateCache.put('url.html', 'WORKS'));
var ng1 = function() { return {templateUrl: 'url.html'}; };
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('WORKS');
ref.dispose();
async.done();
});
}));
it('should support controller with controllerAs',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support controller with controllerAs', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() {
@ -592,23 +629,26 @@ export function main() {
};
};
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('scope; isClass; NG1; published');
ref.dispose();
async.done();
});
}));
it('should support bindToController',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support bindToController', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() {
@ -621,23 +661,26 @@ export function main() {
};
};
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1 title="WORKS"></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1 title="WORKS"></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('WORKS');
ref.dispose();
async.done();
});
}));
it('should support bindToController with bindings',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support bindToController with bindings', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function() {
@ -650,23 +693,26 @@ export function main() {
};
};
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1 title="WORKS"></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1 title="WORKS"></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('WORKS');
ref.dispose();
async.done();
});
}));
it('should support single require in linking fn',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support single require in linking fn', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = function($rootScope: any /** TODO #9100 */) {
@ -688,23 +734,26 @@ export function main() {
};
};
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('WORKS');
ref.dispose();
async.done();
});
}));
it('should support array require in linking fn',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support array require in linking fn', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var parent = function() {
@ -731,23 +780,26 @@ export function main() {
};
ng1Module.directive('parent', parent);
ng1Module.directive('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><parent><ng2></ng2></parent></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('PARENT:WORKS');
ref.dispose();
async.done();
});
}));
it('should call $onInit of components',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should call $onInit of components', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var valueToFind = '$onInit';
@ -759,24 +811,26 @@ export function main() {
};
ng1Module.component('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
var Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
constructor: function() {}
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual(valueToFind);
ref.dispose();
async.done();
});
}));
it('should bind input properties (<) of components',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should bind input properties (<) of components', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = {
@ -786,26 +840,27 @@ export function main() {
};
ng1Module.component('ng1', ng1);
var Ng2 = Component({
selector: 'ng2',
template: '<ng1 [personProfile]="goku"></ng1>',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({
constructor: function() { this.goku = {firstName: 'GOKU', lastName: 'SAN'}; }
});
var Ng2 =
Component({selector: 'ng2', template: '<ng1 [personProfile]="goku"></ng1>'}).Class({
constructor: function() { this.goku = {firstName: 'GOKU', lastName: 'SAN'}; }
});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
var element = html(`<div><ng2></ng2></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual(`Hello GOKU SAN`);
ref.dispose();
async.done();
});
}));
it('should support ng2 > ng1 > ng2',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should support ng2 > ng1 > ng2', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var ng1Module = angular.module('ng1', []);
var ng1 = {
@ -813,22 +868,23 @@ export function main() {
};
ng1Module.component('ng1', ng1);
var Ng2a = Component({
selector: 'ng2a',
template: 'ng2a(<ng1></ng1>)',
directives: [adapter.upgradeNg1Component('ng1')]
}).Class({constructor: function() {}});
ng1Module.directive('ng2a', adapter.downgradeNg2Component(Ng2a));
var Ng2b = Component({selector: 'ng2b', template: 'ng2b', directives: []}).Class({
var Ng2a = Component({selector: 'ng2a', template: 'ng2a(<ng1></ng1>)'}).Class({
constructor: function() {}
});
ng1Module.directive('ng2a', adapter.downgradeNg2Component(Ng2a));
var Ng2b =
Component({selector: 'ng2b', template: 'ng2b'}).Class({constructor: function() {}});
ng1Module.directive('ng2b', adapter.downgradeNg2Component(Ng2b));
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b],
imports: [BrowserModule]
}).Class({constructor: function() {}});
var element = html(`<div><ng2a></ng2a></div>`);
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(multiTrim(document.body.textContent)).toEqual('ng2a(ng1(ng2b))');
async.done();
});
}));
});
@ -837,12 +893,12 @@ export function main() {
function SomeToken() {}
it('should export ng2 instance to ng1', async(() => {
var MyModule = NgModule({
providers: [{provide: SomeToken, useValue: 'correct_value'}],
imports: [BrowserModule]
}).Class({constructor: function() {}});
var MyNg2Module = NgModule({
providers: [{provide: SomeToken, useValue: 'correct_value'}],
imports: [BrowserModule]
}).Class({constructor: function() {}});
var adapter = new UpgradeAdapter(MyModule);
const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module);
var module = angular.module('myExample', []);
module.factory('someToken', adapter.downgradeNg2Provider(SomeToken));
adapter.bootstrap(html('<div>'), ['myExample']).ready((ref) => {
@ -851,9 +907,11 @@ export function main() {
});
}));
it('should export ng1 instance to ng2',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should export ng1 instance to ng2', async(() => {
var MyNg2Module =
NgModule({imports: [BrowserModule]}).Class({constructor: function() {}});
const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module);
var module = angular.module('myExample', []);
module.value('testValue', 'secreteToken');
adapter.upgradeNg1Provider('testValue');
@ -864,15 +922,16 @@ export function main() {
expect(ref.ng2Injector.get(String)).toBe('secreteToken');
expect(ref.ng2Injector.get('testToken')).toBe('secreteToken');
ref.dispose();
async.done();
});
}));
});
describe('testability', () => {
it('should handle deferred bootstrap',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter: UpgradeAdapter = new UpgradeAdapter();
it('should handle deferred bootstrap', async(() => {
var MyNg2Module =
NgModule({imports: [BrowserModule]}).Class({constructor: function() {}});
const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module);
var ng1Module = angular.module('ng1', []);
var bootstrapResumed: boolean = false;
@ -882,7 +941,6 @@ export function main() {
adapter.bootstrap(element, ['ng1']).ready((ref) => {
expect(bootstrapResumed).toEqual(true);
ref.dispose();
async.done();
});
setTimeout(() => {
@ -891,9 +949,11 @@ export function main() {
}, 100);
}));
it('should wait for ng2 testability',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter: UpgradeAdapter = new UpgradeAdapter();
it('should wait for ng2 testability', async(() => {
var MyNg2Module =
NgModule({imports: [BrowserModule]}).Class({constructor: function() {}});
const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module);
var ng1Module = angular.module('ng1', []);
var element = html('<div></div>');
adapter.bootstrap(element, ['ng1']).ready((ref) => {
@ -904,7 +964,6 @@ export function main() {
angular.getTestability(element).whenStable(function() {
expect(ng2Stable).toEqual(true);
ref.dispose();
async.done();
});
setTimeout(() => {
@ -916,9 +975,8 @@ export function main() {
});
describe('examples', () => {
it('should verify UpgradeAdapter example',
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
var adapter = new UpgradeAdapter();
it('should verify UpgradeAdapter example', async(() => {
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
var module = angular.module('myExample', []);
module.directive('ng1', function() {
@ -929,15 +987,18 @@ export function main() {
};
});
var Ng2 =
Component({
selector: 'ng2',
inputs: ['name'],
template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)',
directives: [adapter.upgradeNg1Component('ng1')]
template: 'ng2[<ng1 [title]="name">transclude</ng1>](<ng-content></ng-content>)'
}).Class({constructor: function() {}});
var Ng2Module = NgModule({
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
imports: [BrowserModule]
}).Class({constructor: function() {}});
module.directive('ng2', adapter.downgradeNg2Component(Ng2));
document.body.innerHTML = '<ng2 name="World">project</ng2>';
@ -946,7 +1007,6 @@ export function main() {
expect(multiTrim(document.body.textContent))
.toEqual('ng2[ng1[Hello World!](transclude)](project)');
ref.dispose();
async.done();
});
}));
});

View File

@ -227,8 +227,6 @@ export declare class CollectionChangeRecord {
export declare class Compiler {
clearCache(): void;
clearCacheFor(type: Type<any>): void;
compileComponentAsync<T>(component: Type<T>, ngModule?: Type<any>): Promise<ComponentFactory<T>>;
compileComponentSync<T>(component: Type<T>, ngModule?: Type<any>): ComponentFactory<T>;
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>): Promise<ModuleWithComponentFactories<T>>;
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>;
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>;
@ -276,18 +274,16 @@ export declare abstract class ComponentFactoryResolver {
export declare class ComponentMetadata extends DirectiveMetadata implements ComponentMetadataType {
animations: AnimationEntryMetadata[];
changeDetection: ChangeDetectionStrategy;
directives: Array<Type<any> | any[]>;
encapsulation: ViewEncapsulation;
entryComponents: Array<Type<any> | any[]>;
interpolation: [string, string];
moduleId: string;
pipes: Array<Type<any> | any[]>;
styleUrls: string[];
styles: string[];
template: string;
templateUrl: string;
viewProviders: any[];
constructor({selector, inputs, outputs, host, exportAs, moduleId, providers, viewProviders, changeDetection, queries, templateUrl, template, styleUrls, styles, animations, directives, pipes, encapsulation, interpolation, entryComponents}?: ComponentMetadataType);
constructor({selector, inputs, outputs, host, exportAs, moduleId, providers, viewProviders, changeDetection, queries, templateUrl, template, styleUrls, styles, animations, encapsulation, interpolation, entryComponents}?: ComponentMetadataType);
}
/** @stable */
@ -300,12 +296,10 @@ export interface ComponentMetadataFactory {
export interface ComponentMetadataType extends DirectiveMetadataType {
animations?: AnimationEntryMetadata[];
changeDetection?: ChangeDetectionStrategy;
directives?: Array<Type<any> | any[]>;
encapsulation?: ViewEncapsulation;
entryComponents?: Array<Type<any> | any[]>;
interpolation?: [string, string];
moduleId?: string;
pipes?: Array<Type<any> | any[]>;
styleUrls?: string[];
styles?: string[];
template?: string;

View File

@ -1,6 +1,6 @@
/** @experimental */
export declare class UpgradeAdapter {
constructor(ng2AppModule?: Type<any>);
constructor(ng2AppModule: Type<any>);
bootstrap(element: Element, modules?: any[], config?: angular.IAngularBootstrapConfig): UpgradeAdapterRef;
downgradeNg2Component(type: Type<any>): Function;
downgradeNg2Provider(token: any): Function;