From 8faf6364dc344d53c619a1bdfc1ed4d856375f82 Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Wed, 29 Apr 2015 16:52:34 -0700 Subject: [PATCH] refactor(core): remove DynamicComponent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BREAKING CHANGE: A dynamic component is just a component that has no @View annotation… --- .../src/core/annotations/annotations.es6 | 2 - .../src/core/annotations_impl/annotations.js | 131 ++++++------------ .../angular2/src/core/compiler/compiler.js | 12 +- .../src/core/compiler/proto_view_factory.js | 4 +- .../src/core/compiler/template_resolver.js | 4 +- .../src/core/decorators/decorators.es6 | 7 +- .../src/mock/template_resolver_mock.js | 4 + .../angular2/test/core/application_spec.js | 8 -- .../test/core/compiler/compiler_spec.js | 7 +- .../compiler/dynamic_component_loader_spec.js | 4 +- .../test/core/compiler/integration_spec.js | 2 +- modules/benchmarks/src/costs/index.js | 4 +- .../src/largetable/largetable_benchmark.js | 2 +- .../src/naive_infinite_scroll/app.js | 2 +- .../src/naive_infinite_scroll/cells.js | 2 +- .../src/naive_infinite_scroll/scroll_area.js | 2 +- .../src/naive_infinite_scroll/scroll_item.js | 2 +- 17 files changed, 76 insertions(+), 123 deletions(-) diff --git a/modules/angular2/src/core/annotations/annotations.es6 b/modules/angular2/src/core/annotations/annotations.es6 index e284f932c3..256276c3b1 100644 --- a/modules/angular2/src/core/annotations/annotations.es6 +++ b/modules/angular2/src/core/annotations/annotations.es6 @@ -7,7 +7,5 @@ export { Component as ComponentAnnotation, Decorator as DecoratorAnnotation, Directive as DirectiveAnnotation, - DynamicComponent as DynamicComponentAnnotation, - Viewport as ViewportAnnotation, onDestroy, onChange, onAllChangesDone } from '../annotations_impl/annotations'; diff --git a/modules/angular2/src/core/annotations_impl/annotations.js b/modules/angular2/src/core/annotations_impl/annotations.js index fbd4f5173b..80400469f4 100644 --- a/modules/angular2/src/core/annotations_impl/annotations.js +++ b/modules/angular2/src/core/annotations_impl/annotations.js @@ -8,7 +8,7 @@ import {DEFAULT} from 'angular2/change_detection'; /** * Directives allow you to attach behavior to elements in the DOM. * - * Directive is an abstract concept, instead use concrete directives: {@link Component}, {@link DynamicComponent}, {@link Decorator}. + * Directive is an abstract concept, instead use concrete directives: {@link Component}, or {@link Decorator}. * * A directive consists of a single directive annotation and a controller class. When the directive's `selector` matches * elements in the DOM, the following steps occur: @@ -542,6 +542,51 @@ export class Directive extends Injectable { * } * ``` * + * + * Dynamically loading a component at runtime: + * + * Regular Angular components are statically resolved. Dynamic components allows to resolve a component at runtime + * instead by providing a placeholder into which a regular Angular component can be dynamically loaded. Once loaded, + * the dynamically-loaded component becomes permanent and cannot be changed. + * Dynamic components are declared just like components, but without a `@View` annotation. + * + * + * ## Example + * + * Here we have `DynamicComp` which acts as the placeholder for `HelloCmp`. At runtime, the dynamic component + * `DynamicComp` requests loading of the `HelloCmp` component. + * + * There is nothing special about `HelloCmp`, which is a regular Angular component. It can also be used in other static + * locations. + * + * ``` + * @Component({ + * selector: 'dynamic-comp' + * }) + * class DynamicComp { + * helloCmp:HelloCmp; + * constructor(loader:DynamicComponentLoader, location:ElementRef) { + * loader.load(HelloCmp, location).then((helloCmp) => { + * this.helloCmp = helloCmp; + * }); + * } + * } + * + * @Component({ + * selector: 'hello-cmp' + * }) + * @View({ + * template: "{{greeting}}" + * }) + * class HelloCmp { + * greeting:string; + * constructor() { + * this.greeting = "hello"; + * } + * } + * ``` + * + * * @exportedAs angular2/annotations */ export class Component extends Directive { @@ -639,90 +684,6 @@ export class Component extends Directive { } } -/** - * Directive used for dynamically loading components. - * - * Regular Angular components are statically resolved. DynamicComponent allows to you resolve a component at runtime - * instead by providing a placeholder into which a regular Angular component can be dynamically loaded. Once loaded, - * the dynamically-loaded component becomes permanent and cannot be changed. - * - * - * ## Example - * - * Here we have `DynamicComp` which acts as the placeholder for `HelloCmp`. At runtime, the dynamic component - * `DynamicComp` requests loading of the `HelloCmp` component. - * - * There is nothing special about `HelloCmp`, which is a regular Angular component. It can also be used in other static - * locations. - * - * ``` - * @DynamicComponent({ - * selector: 'dynamic-comp' - * }) - * class DynamicComp { - * helloCmp:HelloCmp; - * constructor(loader:DynamicComponentLoader, location:PrivateComponentLocation) { - * loader.load(HelloCmp, location).then((helloCmp) => { - * this.helloCmp = helloCmp; - * }); - * } - * } - * - * @Component({ - * selector: 'hello-cmp' - * }) - * @View({ - * template: "{{greeting}}" - * }) - * class HelloCmp { - * greeting:string; - * constructor() { - * this.greeting = "hello"; - * } - * } - * ``` - * - * - * - * @exportedAs angular2/annotations - */ -export class DynamicComponent extends Directive { - /** - * Same as `injectables` in the {@link Component}. - */ - // TODO(vsankin): Please extract into AbstractComponent - injectables:any; //List; - - @CONST() - constructor({ - selector, - properties, - events, - hostListeners, - hostProperties, - injectables, - lifecycle - }:{ - selector:string, - properties:any, - events:List, - hostListeners:any, - hostProperties:any, - injectables:List, - lifecycle:List - }={}) { - super({ - selector: selector, - properties: properties, - events: events, - hostListeners: hostListeners, - hostProperties: hostProperties, - lifecycle: lifecycle - }); - - this.injectables = injectables; - } -} /** * Directive that attaches behavior to DOM elements. diff --git a/modules/angular2/src/core/compiler/compiler.js b/modules/angular2/src/core/compiler/compiler.js index d5f0f99efd..bd0d3d1602 100644 --- a/modules/angular2/src/core/compiler/compiler.js +++ b/modules/angular2/src/core/compiler/compiler.js @@ -4,7 +4,7 @@ import {Promise, PromiseWrapper} from 'angular2/src/facade/async'; import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection'; import {DirectiveMetadataReader} from './directive_metadata_reader'; -import {Component, DynamicComponent, Decorator} from '../annotations_impl/annotations'; +import {Component, Decorator} from '../annotations_impl/annotations'; import {AppProtoView} from './view'; import {ProtoViewRef} from './view_ref'; import {DirectiveBinding} from './element_injector'; @@ -128,8 +128,10 @@ export class Compiler { // It happens when a template references a component multiple times. return pvPromise; } - var template = this._templateResolver.resolve(component); + if (isBlank(template)) { + return null; + } if (isPresent(template.renderer)) { var directives = []; pvPromise = this._renderer.createImperativeComponentProtoView(template.renderer).then( (renderPv) => { @@ -174,9 +176,7 @@ export class Compiler { }; var nestedCall = null; if (isPresent(nestedComponent)) { - if (!(nestedComponent.annotation instanceof DynamicComponent)) { - nestedCall = this._compile(nestedComponent); - } + nestedCall = this._compile(nestedComponent); } else if (isPresent(nestedRenderProtoView)) { nestedCall = this._compileNestedProtoViews(componentBinding, nestedRenderProtoView, directives, false); } @@ -231,7 +231,7 @@ export class Compiler { var ann = directiveBinding.annotation; var renderType; var compileChildren = true; - if ((ann instanceof Component) || (ann instanceof DynamicComponent)) { + if (ann instanceof Component) { renderType = renderApi.DirectiveMetadata.COMPONENT_TYPE; } else if (ann instanceof Decorator) { renderType = renderApi.DirectiveMetadata.DECORATOR_TYPE; diff --git a/modules/angular2/src/core/compiler/proto_view_factory.js b/modules/angular2/src/core/compiler/proto_view_factory.js index 5a6df8946f..7d44cacf54 100644 --- a/modules/angular2/src/core/compiler/proto_view_factory.js +++ b/modules/angular2/src/core/compiler/proto_view_factory.js @@ -4,7 +4,7 @@ import {isPresent, isBlank} from 'angular2/src/facade/lang'; import {reflector} from 'angular2/src/reflection/reflection'; import {ChangeDetection, DirectiveIndex} from 'angular2/change_detection'; -import {Component, DynamicComponent} from '../annotations_impl/annotations'; +import {Component} from '../annotations_impl/annotations'; import * as renderApi from 'angular2/src/render/api'; import {AppProtoView} from './view'; @@ -162,7 +162,7 @@ class SortedDirectives { this.componentDirective = null; ListWrapper.forEach(renderDirectives, (renderDirectiveBinder) => { var directiveBinding = allDirectives[renderDirectiveBinder.directiveIndex]; - if ((directiveBinding.annotation instanceof Component) || (directiveBinding.annotation instanceof DynamicComponent)) { + if (directiveBinding.annotation instanceof Component) { // component directives need to be the first binding in ElementInjectors! this.componentDirective = directiveBinding; ListWrapper.insert(this.renderDirectives, 0, renderDirectiveBinder); diff --git a/modules/angular2/src/core/compiler/template_resolver.js b/modules/angular2/src/core/compiler/template_resolver.js index bb3ec38ae0..d0a055d7ee 100644 --- a/modules/angular2/src/core/compiler/template_resolver.js +++ b/modules/angular2/src/core/compiler/template_resolver.js @@ -34,7 +34,7 @@ export class TemplateResolver { return annotation; } } - - throw new BaseException(`No template found for ${stringify(component)}`); + // No annotation = dynamic component! + return null; } } diff --git a/modules/angular2/src/core/decorators/decorators.es6 b/modules/angular2/src/core/decorators/decorators.es6 index a595fd0b5a..175e68f2d8 100644 --- a/modules/angular2/src/core/decorators/decorators.es6 +++ b/modules/angular2/src/core/decorators/decorators.es6 @@ -1,8 +1,7 @@ import { ComponentAnnotation, - DecoratorAnnotation, - DynamicComponentAnnotation, - ViewportAnnotation} from '../annotations/annotations'; + DecoratorAnnotation +} from '../annotations/annotations'; import {ViewAnnotation} from '../annotations/view'; import {AncestorAnnotation, ParentAnnotation} from '../annotations/visibility'; import {AttributeAnnotation, QueryAnnotation} from '../annotations/di'; @@ -25,8 +24,6 @@ function makeDecorator(annotationCls) { /* from annotations */ export var Component = makeDecorator(ComponentAnnotation); export var Decorator = makeDecorator(DecoratorAnnotation); -export var DynamicComponent = makeDecorator(DynamicComponentAnnotation); -export var Viewport = makeDecorator(ViewportAnnotation); /* from di */ export var Attribute = makeDecorator(AttributeAnnotation); diff --git a/modules/angular2/src/mock/template_resolver_mock.js b/modules/angular2/src/mock/template_resolver_mock.js index af8e8e5871..51862abcca 100644 --- a/modules/angular2/src/mock/template_resolver_mock.js +++ b/modules/angular2/src/mock/template_resolver_mock.js @@ -78,6 +78,10 @@ export class MockTemplateResolver extends TemplateResolver { if (isBlank(view)) { view = super.resolve(component); } + if (isBlank(view)) { + // dynamic components + return null; + } var directives = view.directives; var overrides = MapWrapper.get(this._directiveOverrides, component); diff --git a/modules/angular2/test/core/application_spec.js b/modules/angular2/test/core/application_spec.js index 4fecad7294..db8f57456a 100644 --- a/modules/angular2/test/core/application_spec.js +++ b/modules/angular2/test/core/application_spec.js @@ -87,14 +87,6 @@ export function main() { }); describe('bootstrap factory method', () => { - it('should throw if no View found', inject([AsyncTestCompleter], (async) => { - var refPromise = bootstrap(HelloRootMissingTemplate, testBindings, (e,t) => {throw e;}); - PromiseWrapper.then(refPromise, null, (reason) => { - expect(reason.message).toContain('No template found for HelloRootMissingTemplate'); - async.done(); - }); - })); - it('should throw if bootstrapped Directive is not a Component', inject([AsyncTestCompleter], (async) => { var refPromise = bootstrap(HelloRootDirectiveIsNotCmp, testBindings, (e,t) => {throw e;}); PromiseWrapper.then(refPromise, null, (reason) => { diff --git a/modules/angular2/test/core/compiler/compiler_spec.js b/modules/angular2/test/core/compiler/compiler_spec.js index 110b48e9c5..ac0d383d97 100644 --- a/modules/angular2/test/core/compiler/compiler_spec.js +++ b/modules/angular2/test/core/compiler/compiler_spec.js @@ -21,7 +21,7 @@ import {Compiler, CompilerCache} from 'angular2/src/core/compiler/compiler'; import {AppProtoView} from 'angular2/src/core/compiler/view'; import {ElementBinder} from 'angular2/src/core/compiler/element_binder'; import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader'; -import {Component, DynamicComponent, Decorator} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {Attribute} from 'angular2/src/core/annotations_impl/di'; import {View} from 'angular2/src/core/annotations_impl/view'; import {internalProtoView} from 'angular2/src/core/compiler/view_ref'; @@ -490,7 +490,7 @@ class NestedComponent {} class RecursiveComponent {} -@DynamicComponent() +@Component() class SomeDynamicComponentDirective {} @Decorator() @@ -554,7 +554,8 @@ class FakeTemplateResolver extends TemplateResolver { resolve(component: Type): View { var template = MapWrapper.get(this._cmpTemplates, component); if (isBlank(template)) { - throw 'No template'; + // dynamic component + return null; } return template; } diff --git a/modules/angular2/test/core/compiler/dynamic_component_loader_spec.js b/modules/angular2/test/core/compiler/dynamic_component_loader_spec.js index 65e966e1e9..d06bb7a115 100644 --- a/modules/angular2/test/core/compiler/dynamic_component_loader_spec.js +++ b/modules/angular2/test/core/compiler/dynamic_component_loader_spec.js @@ -16,7 +16,7 @@ import { import {TestBed} from 'angular2/src/test_lib/test_bed'; -import {Decorator, Component, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Decorator, Component} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; import {DynamicComponentLoader} from 'angular2/src/core/compiler/dynamic_component_loader'; import {ElementRef} from 'angular2/src/core/compiler/element_ref'; @@ -229,7 +229,7 @@ class ChildComp { class DynamicallyCreatedComponentService { } -@DynamicComponent({ +@Component({ selector: 'dynamic-comp' }) class DynamicComp { diff --git a/modules/angular2/test/core/compiler/integration_spec.js b/modules/angular2/test/core/compiler/integration_spec.js index edf6a3bfe8..03072177f5 100644 --- a/modules/angular2/test/core/compiler/integration_spec.js +++ b/modules/angular2/test/core/compiler/integration_spec.js @@ -24,7 +24,7 @@ import {Injector, bind} from 'angular2/di'; import {PipeRegistry, defaultPipeRegistry, ChangeDetection, DynamicChangeDetection, Pipe, ChangeDetectorRef, ON_PUSH} from 'angular2/change_detection'; -import {Decorator, Component, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Decorator, Component} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; import {Parent, Ancestor} from 'angular2/src/core/annotations_impl/visibility'; import {Attribute} from 'angular2/src/core/annotations_impl/di'; diff --git a/modules/benchmarks/src/costs/index.js b/modules/benchmarks/src/costs/index.js index 69d9a7ca64..7cc22ef668 100644 --- a/modules/benchmarks/src/costs/index.js +++ b/modules/benchmarks/src/costs/index.js @@ -12,7 +12,7 @@ import {If, For} from 'angular2/directives'; // TODO(radokirov): Once the application is transpiled by TS instead of Traceur, // add those imports back into 'angular2/angular2'; -import {Component, Decorator, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; var testList = null; @@ -109,7 +109,7 @@ class DummyComponent {} @Decorator({selector: '[dummy-decorator]'}) class DummyDecorator {} -@DynamicComponent({selector: 'dynamic-dummy'}) +@Component({selector: 'dynamic-dummy'}) class DynamicDummy { constructor(loader:DynamicComponentLoader, location:ElementRef) { loader.loadIntoExistingLocation(DummyComponent, location); diff --git a/modules/benchmarks/src/largetable/largetable_benchmark.js b/modules/benchmarks/src/largetable/largetable_benchmark.js index 28d603a4d7..a3030d53c5 100644 --- a/modules/benchmarks/src/largetable/largetable_benchmark.js +++ b/modules/benchmarks/src/largetable/largetable_benchmark.js @@ -2,7 +2,7 @@ import {bootstrap} from 'angular2/angular2'; // TODO(radokirov): Once the application is transpiled by TS instead of Traceur, // add those imports back into 'angular2/angular2'; -import {Component, Decorator, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle'; diff --git a/modules/benchmarks/src/naive_infinite_scroll/app.js b/modules/benchmarks/src/naive_infinite_scroll/app.js index d0450f1c9f..9854bfc8c4 100644 --- a/modules/benchmarks/src/naive_infinite_scroll/app.js +++ b/modules/benchmarks/src/naive_infinite_scroll/app.js @@ -9,7 +9,7 @@ import {document} from 'angular2/src/facade/browser'; // TODO(radokirov): Once the application is transpiled by TS instead of Traceur, // add those imports back into 'angular2/angular2'; -import {Component, Decorator, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; @Component({selector: 'scroll-app'}) diff --git a/modules/benchmarks/src/naive_infinite_scroll/cells.js b/modules/benchmarks/src/naive_infinite_scroll/cells.js index 5338dc3cde..fdb0b9d959 100644 --- a/modules/benchmarks/src/naive_infinite_scroll/cells.js +++ b/modules/benchmarks/src/naive_infinite_scroll/cells.js @@ -5,7 +5,7 @@ import {For} from 'angular2/directives'; // TODO(radokirov): Once the application is transpiled by TS instead of Traceur, // add those imports back into 'angular2/angular2'; -import {Component, Decorator, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; export class HasStyle { diff --git a/modules/benchmarks/src/naive_infinite_scroll/scroll_area.js b/modules/benchmarks/src/naive_infinite_scroll/scroll_area.js index 0502648f25..b034466fb0 100644 --- a/modules/benchmarks/src/naive_infinite_scroll/scroll_area.js +++ b/modules/benchmarks/src/naive_infinite_scroll/scroll_area.js @@ -3,7 +3,7 @@ import {Math} from 'angular2/src/facade/math'; // TODO(radokirov): Once the application is transpiled by TS instead of Traceur, // add those imports back into 'angular2/angular2'; -import {Component, Decorator, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; import {Offering, ITEMS, ITEM_HEIGHT, VISIBLE_ITEMS, VIEW_PORT_HEIGHT, diff --git a/modules/benchmarks/src/naive_infinite_scroll/scroll_item.js b/modules/benchmarks/src/naive_infinite_scroll/scroll_item.js index 57c9f9b627..e1c2982470 100644 --- a/modules/benchmarks/src/naive_infinite_scroll/scroll_item.js +++ b/modules/benchmarks/src/naive_infinite_scroll/scroll_item.js @@ -5,7 +5,7 @@ import {CompanyNameComponent, OpportunityNameComponent, // TODO(radokirov): Once the application is transpiled by TS instead of Traceur, // add those imports back into 'angular2/angular2'; -import {Component, Decorator, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations'; +import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotations'; import {View} from 'angular2/src/core/annotations_impl/view'; import {Offering, ITEM_HEIGHT, COMPANY_NAME_WIDTH, OPPORTUNITY_NAME_WIDTH,