X Tutup
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 0 additions & 48 deletions modules/angular2/src/core/annotations_impl/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -848,54 +848,6 @@ export interface ComponentArgs {
* ```
*
*
* 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
*/
@CONST()
Expand Down
64 changes: 37 additions & 27 deletions modules/angular2/src/core/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import * as renderApi from 'angular2/src/render/api';
@Injectable()
export class CompilerCache {
_cache: Map<Type, AppProtoView> = MapWrapper.create();
_hostCache: Map<Type, AppProtoView> = MapWrapper.create();

set(component: Type, protoView: AppProtoView): void {
MapWrapper.set(this._cache, component, protoView);
Expand All @@ -43,7 +44,19 @@ export class CompilerCache {
return normalizeBlank(result);
}

clear(): void { MapWrapper.clear(this._cache); }
setHost(component: Type, protoView: AppProtoView): void {
MapWrapper.set(this._hostCache, component, protoView);
}

getHost(component: Type): AppProtoView {
var result = MapWrapper.get(this._hostCache, component);
return normalizeBlank(result);
}

clear(): void {
MapWrapper.clear(this._cache);
MapWrapper.clear(this._hostCache);
}
}

/**
Expand Down Expand Up @@ -94,20 +107,19 @@ export class Compiler {
Compiler._assertTypeIsComponent(componentBinding);

var directiveMetadata = componentBinding.metadata;
return this._render.compileHost(directiveMetadata)
.then((hostRenderPv) => {
return this._compileNestedProtoViews(componentBinding, hostRenderPv, [componentBinding]);
})
.then((appProtoView) => { return new ProtoViewRef(appProtoView); });
}

compile(component: Type): Promise<ProtoViewRef> {
var componentBinding = this._bindDirective(component);
Compiler._assertTypeIsComponent(componentBinding);
var pvOrPromise = this._compile(componentBinding);
var pvPromise = isPromise(pvOrPromise) ? <Promise<AppProtoView>>pvOrPromise :
PromiseWrapper.resolve(pvOrPromise);
return pvPromise.then((appProtoView) => { return new ProtoViewRef(appProtoView); });
var hostPvPromise;
var component = <Type>componentBinding.key.token;
var hostAppProtoView = this._compilerCache.getHost(component);
if (isPresent(hostAppProtoView)) {
hostPvPromise = PromiseWrapper.resolve(hostAppProtoView);
} else {
hostPvPromise = this._render.compileHost(directiveMetadata)
.then((hostRenderPv) => {
return this._compileNestedProtoViews(componentBinding, hostRenderPv,
[componentBinding]);
});
}
return hostPvPromise.then((hostAppProtoView) => { return new ProtoViewRef(hostAppProtoView); });
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe remove {

}

private _compile(componentBinding: DirectiveBinding): Promise<AppProtoView>| AppProtoView {
Expand All @@ -128,9 +140,6 @@ export class Compiler {
return pvPromise;
}
var template = this._templateResolver.resolve(component);
if (isBlank(template)) {
return null;
}

var directives = this._flattenDirectives(template);

Expand Down Expand Up @@ -160,16 +169,17 @@ export class Compiler {
var protoViews =
this._protoViewFactory.createAppProtoViews(componentBinding, renderPv, directives);
var protoView = protoViews[0];
// TODO(tbosch): we should be caching host protoViews as well!
// -> need a separate cache for this...
if (renderPv.type === renderApi.ViewType.COMPONENT && isPresent(componentBinding)) {
// Populate the cache before compiling the nested components,
// so that components can reference themselves in their template.
if (isPresent(componentBinding)) {
var component = componentBinding.key.token;
this._compilerCache.set(component, protoView);
MapWrapper.delete(this._compiling, component);
if (renderPv.type === renderApi.ViewType.COMPONENT) {
// Populate the cache before compiling the nested components,
// so that components can reference themselves in their template.
this._compilerCache.set(component, protoView);
MapWrapper.delete(this._compiling, component);
} else {
this._compilerCache.setHost(component, protoView);
}
}

var nestedPVPromises = [];
ListWrapper.forEach(this._collectComponentElementBinders(protoViews), (elementBinder) => {
var nestedComponent = elementBinder.componentDirective;
Expand All @@ -179,7 +189,7 @@ export class Compiler {
if (isPromise(nestedCall)) {
ListWrapper.push(nestedPVPromises,
(<Promise<AppProtoView>>nestedCall).then(elementBinderDone));
} else if (isPresent(nestedCall)) {
} else {
elementBinderDone(<AppProtoView>nestedCall);
}
});
Expand Down
85 changes: 25 additions & 60 deletions modules/angular2/src/core/compiler/dynamic_component_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,31 +25,14 @@ export class ComponentRef {
export class DynamicComponentLoader {
constructor(private _compiler: Compiler, private _viewManager: AppViewManager) {}

/**
* Loads a component into the location given by the provided ElementRef. The loaded component
* receives injection as if it in the place of the provided ElementRef.
*/
loadIntoExistingLocation(typeOrBinding, location: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compile(binding.token)
.then(componentProtoViewRef => {
this._viewManager.createDynamicComponentView(location, componentProtoViewRef, binding,
injector);
var component = this._viewManager.getComponent(location);
var dispose = () => { this._viewManager.destroyDynamicComponent(location); };
return new ComponentRef(location, component, dispose);
});
}

/**
* Loads a root component that is placed at the first element that matches the
* component's selector.
* The loaded component receives injection normally as a hosted view.
*/
loadAsRoot(typeOrBinding, overrideSelector: string = null,
loadAsRoot(typeOrBinding: Type | Binding, overrideSelector: string = null,
injector: Injector = null): Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding))
return this._compiler.compileInHost(typeOrBinding)
.then(hostProtoViewRef => {
var hostViewRef =
this._viewManager.createRootHostView(hostProtoViewRef, overrideSelector, injector);
Expand All @@ -62,55 +45,37 @@ export class DynamicComponentLoader {
}

/**
* Loads a component into a free host view that is not yet attached to
* a parent on the render side, although it is attached to a parent in the injector hierarchy.
* The loaded component receives injection normally as a hosted view.
* Loads a component into the component view of the provided ElementRef
* next to the element with the given name
* The loaded component receives
* injection normally as a hosted view.
*/
loadIntoNewLocation(typeOrBinding, parentComponentLocation: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
return this._compiler.compileInHost(this._getBinding(typeOrBinding))
loadIntoLocation(typeOrBinding: Type | Binding, hostLocation: ElementRef, anchorName: string,
injector: Injector = null): Promise<ComponentRef> {
return this.loadNextToLocation(
typeOrBinding, this._viewManager.getNamedElementInComponentView(hostLocation, anchorName),
injector);
}

/**
* Loads a component next to the provided ElementRef. The loaded component receives
* injection normally as a hosted view.
*/
loadNextToLocation(typeOrBinding: Type | Binding, location: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
return this._compiler.compileInHost(typeOrBinding)
.then(hostProtoViewRef => {
var hostViewRef = this._viewManager.createFreeHostView(parentComponentLocation,
hostProtoViewRef, injector);
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef =
viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);

var dispose = () => {
this._viewManager.destroyFreeHostView(parentComponentLocation, hostViewRef);
var index = viewContainer.indexOf(hostViewRef);
viewContainer.remove(index);
};
return new ComponentRef(newLocation, component, dispose);
});
}

/**
* Loads a component next to the provided ElementRef. The loaded component receives
* injection normally as a hosted view.
*/
loadNextToExistingLocation(typeOrBinding, location: ElementRef,
injector: Injector = null): Promise<ComponentRef> {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compileInHost(binding).then(hostProtoViewRef => {
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef =
viewContainer.create(hostProtoViewRef, viewContainer.length, null, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);

var dispose = () => {
var index = viewContainer.indexOf(hostViewRef);
viewContainer.remove(index);
};
return new ComponentRef(newLocation, component, dispose);
});
}

private _getBinding(typeOrBinding): Binding {
var binding;
if (typeOrBinding instanceof Binding) {
binding = typeOrBinding;
} else {
binding = bind(typeOrBinding).toClass(typeOrBinding);
}
return binding;
}
}
4 changes: 0 additions & 4 deletions modules/angular2/src/core/compiler/element_binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ export class ElementBinder {
return isPresent(this.componentDirective) && isPresent(this.nestedProtoView);
}

hasDynamicComponent() {
return isPresent(this.componentDirective) && isBlank(this.nestedProtoView);
}

hasEmbeddedProtoView() {
return !isPresent(this.componentDirective) && isPresent(this.nestedProtoView);
}
Expand Down
46 changes: 2 additions & 44 deletions modules/angular2/src/core/compiler/element_injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,9 +662,6 @@ export class ElementInjector extends TreeNode<ElementInjector> {
private _preBuiltObjects = null;
private _constructionCounter: number = 0;

private _dynamicallyCreatedComponent: any;
private _dynamicallyCreatedComponentBinding: DirectiveBinding;

// Queries are added during construction or linking with a new parent.
// They are never removed.
private _query0: QueryRef;
Expand Down Expand Up @@ -693,20 +690,10 @@ export class ElementInjector extends TreeNode<ElementInjector> {
this._lightDomAppInjector = null;
this._shadowDomAppInjector = null;
this._strategy.callOnDestroy();
this.destroyDynamicComponent();
this._strategy.clearInstances();
this._constructionCounter = 0;
}

destroyDynamicComponent(): void {
if (isPresent(this._dynamicallyCreatedComponentBinding) &&
this._dynamicallyCreatedComponentBinding.callOnDestroy) {
this._dynamicallyCreatedComponent.onDestroy();
this._dynamicallyCreatedComponentBinding = null;
this._dynamicallyCreatedComponent = null;
}
}

onAllChangesDone(): void {
if (isPresent(this._query0) && this._query0.originator === this)
this._query0.list.fireCallbacks();
Expand Down Expand Up @@ -743,14 +730,6 @@ export class ElementInjector extends TreeNode<ElementInjector> {
}
}

dynamicallyCreateComponent(componentDirective: DirectiveBinding, parentInjector: Injector): any {
this._shadowDomAppInjector =
this._createShadowDomAppInjector(componentDirective, parentInjector);
this._dynamicallyCreatedComponentBinding = componentDirective;
this._dynamicallyCreatedComponent = this._new(this._dynamicallyCreatedComponentBinding);
return this._dynamicallyCreatedComponent;
}

private _checkShadowDomAppInjector(shadowDomAppInjector: Injector): void {
if (this._proto._firstBindingIsComponent && isBlank(shadowDomAppInjector)) {
throw new BaseException(
Expand All @@ -761,18 +740,7 @@ export class ElementInjector extends TreeNode<ElementInjector> {
}
}

get(token): any {
if (this._isDynamicallyLoadedComponent(token)) {
return this._dynamicallyCreatedComponent;
}

return this._getByKey(Key.get(token), self, false, null);
}

private _isDynamicallyLoadedComponent(token): boolean {
return isPresent(this._dynamicallyCreatedComponentBinding) &&
Key.get(token) === this._dynamicallyCreatedComponentBinding.key;
}
get(token): any { return this._getByKey(Key.get(token), self, false, null); }

hasDirective(type: Type): boolean {
return this._strategy.getObjByKeyId(Key.get(type).id, LIGHT_DOM_AND_SHADOW_DOM) !== _undefined;
Expand All @@ -796,17 +764,10 @@ export class ElementInjector extends TreeNode<ElementInjector> {
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef());
}

getDynamicallyLoadedComponent(): any { return this._dynamicallyCreatedComponent; }

directParent(): ElementInjector { return this._proto.distanceToParent < 2 ? this.parent : null; }

private _isComponentKey(key: Key): boolean { return this._strategy.isComponentKey(key); }

private _isDynamicallyLoadedComponentKey(key: Key): boolean {
return isPresent(this._dynamicallyCreatedComponentBinding) &&
key.id === this._dynamicallyCreatedComponentBinding.key.id;
}

_new(binding: ResolvedBinding): any {
if (this._constructionCounter++ > this._strategy.getMaxDirectives()) {
throw new CyclicDependencyError(binding.key);
Expand Down Expand Up @@ -1113,8 +1074,6 @@ export class ElementInjector extends TreeNode<ElementInjector> {

if (isPresent(this._host) && this._host._isComponentKey(key)) {
return this._host.getComponent();
} else if (isPresent(this._host) && this._host._isDynamicallyLoadedComponentKey(key)) {
return this._host.getDynamicallyLoadedComponent();
} else if (optional) {
return this._appInjector(requestor).getOptional(key);
} else {
Expand All @@ -1123,8 +1082,7 @@ export class ElementInjector extends TreeNode<ElementInjector> {
}

private _appInjector(requestor: Key): Injector {
if (isPresent(requestor) &&
(this._isComponentKey(requestor) || this._isDynamicallyLoadedComponentKey(requestor))) {
if (isPresent(requestor) && this._isComponentKey(requestor)) {
return this._shadowDomAppInjector;
} else {
return this._lightDomAppInjector;
Expand Down
Loading
X Tutup