refactor(compiler): remove `Viewport` directives, use `Decorator` instead

BREAKING_CHANGE:
- The special type of `Viewport` directives is removed
  in favor of a more general `Decorator` directive
- `ViewContainerRef` now no more has a default `ProtoViewRef`
  but requires an explicit one when creating views.

Closes #1536
This commit is contained in:
Tobias Bosch 2015-04-29 15:07:55 -07:00
parent fb67e37339
commit 3aac2fefd7
35 changed files with 280 additions and 366 deletions

View File

@ -5,7 +5,7 @@ projected to DOM as well as which DOM events should invoke which methods on the
syntax which is core to Angular and allows for data-binding, event-binding, template-instantiation.
The design of the template syntax has these properties:
* All data-binding expressions are easily identifiable. (i.e. there is never an ambiguity whether the value should be
interpreted as string literal or as an expression.)
@ -372,8 +372,8 @@ Where:
inserted. The template can be defined implicitly with `template` attribute, which turns the current element into
a template, or explicitly with `<template>` element. Explicit declaration is longer, but it allows for having
templates which have more than one root DOM node.
* `viewport` is required for templates. The Viewport directive is responsible for deciding when
and in which order should child views be inserted into this location. An Viewport directive usually has one or
* `viewport` is required for templates. The directive is responsible for deciding when
and in which order should child views be inserted into this location. Such a directive usually has one or
more bindings and can be represented as either `viewport-directive-bindings` or
`viewport-directive-microsyntax` on `template` element or attribute. See template microsyntax for more details.
@ -387,7 +387,7 @@ Hello {{user}}!
</div>
```
In the above example the `if` Viewport determines whether the child view (an instance of the child template) should be
In the above example the `if` directive determines whether the child view (an instance of the child template) should be
inserted into the root view. The `if` makes this decision based on if the `isAdministrator` binding is true.
The above example is in the short form, for better clarity let's rewrite it in the canonical form, which is functionally
@ -402,8 +402,6 @@ Hello {{user}}!
</template>
```
NOTE: Only Viewport directives can be placed on the template element. (Decorators and Components are not allowed.)
### Template Microsyntax
@ -514,7 +512,7 @@ Where:
* `some-element` Any element which can generate DOM events (or has an angular directive which generates the event).
* `some-event` (escaped with `()` or `on-`) is the name of the event `some-event`. In this case the
dash-case is converted into camel-case `someEvent`.
* `statement` is a valid statement (as defined in section below).
* `statement` is a valid statement (as defined in section below).
If the execution of the statement returns `false`, then `preventDefault`is applied on the DOM event.
By default, angular only listens to the element on the event, and ignores events which bubble. To listen to bubbled

View File

@ -10,7 +10,6 @@ There are three different kinds of directives (described in more detail in later
1. *Decorators*: can be placed on any DOM element and can be combined with other directives.
2. *Components*: Components have an encapsulated view and can configure injectors.
3. *Viewport*: is responsible for adding or removing child views in a parent view. (i.e. for, if)
@ -163,21 +162,19 @@ Example of usage:
## Viewport
## Directives that use a ViewContainer
Viewport is a directive which can control instantiation of child views which are then inserted into the DOM. (Examples are `if` and `for`.)
Directives that use a ViewContainer can control instantiation of child views which are then inserted into the DOM. (Examples are `if` and `for`.)
* Viewports can only be placed on `<template>` elements (or the short hand version which uses `<element template>` attribute.)
* Only one viewport can be present per DOM template element.
* The viewport is created over the `template` element. This is known as the `ViewContainerRef`.
* Viewport can insert child views into the `ViewContainerRef`. The child views show up as siblings of the `Viewport` in the DOM.
* Every `template` element creates a `ProtoView` which can be used to create Views via the ViewContainer.
* The child views show up as siblings of the directive in the DOM.
>> TODO(misko): Relationship with Injection
>> TODO(misko): Instantiator can not be injected into child Views
```
@Viewport({
@Directive({
selector: '[if]',
properties: {
'condition': 'if'
@ -185,17 +182,19 @@ Viewport is a directive which can control instantiation of child views which are
})
export class If {
viewContainer: ViewContainerRef;
protoViewRef: ProtoViewRef;
view: View;
constructor(viewContainer: ViewContainerRef) {
constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) {
this.viewContainer = viewContainer;
this.protoViewRef = protoViewRef;
this.view = null;
}
set condition(value) {
if (value) {
if (this.view === null) {
this.view = this.viewContainer.create();
this.view = this.viewContainer.create(protoViewRef);
}
} else {
if (this.view !== null) {
@ -342,7 +341,7 @@ Shadow DOM provides an encapsulation for components, so as a general rule it doe
})
class Kid {
constructor(
@Parent() dad:Dad,
@Parent() dad:Dad,
@Optional() grandpa:Grandpa
) {
this.name = 'Billy';
@ -365,7 +364,7 @@ class Dad {
this.dad = dad.name;
console.log(dad)
}
}
}
@Component({
selector: '[grandpa]',
@ -379,17 +378,17 @@ class Grandpa {
constructor() {
this.name = 'Joe';
}
}
}
```
Assume the following DOM structure for `grandpa.html`: The Dad has access to the Grandpa.
```
Name: {{name}}: <br> Children: <div dad></div>
Name: {{name}}: <br> Children: <div dad></div>
```
Assume the following DOM structure for `dad.html`: Here the rendered Kid will also have access to Grandpa.
```
Name: {{name}}: <br> Dad: {{dad}} <br> Children: <div kid></div>
Name: {{name}}: <br> Dad: {{dad}} <br> Children: <div kid></div>
```
## Further Reading

View File

@ -4,8 +4,8 @@
This document explains the concept of a View.
A View is a core primitive used by angular to render the DOM tree.
A ViewPort is location in a View which can accept child Views.
Every ViewPort has an associated ViewContainerRef than can contain any number of child Views.
A ViewContainer is location in a View which can accept child Views.
Every ViewContainer has an associated ViewContainerRef than can contain any number of child Views.
Views form a tree structure which mimics the DOM tree.
* View is a core rendering construct. A running application is just a collection of Views which are
@ -15,7 +15,7 @@ Views form a tree structure which mimics the DOM tree.
* Views represent a running instance of a DOM View. This implies that while elements in a View
can change properties, they can not change structurally. (Structural changes such as, adding or
removing elements requires adding or removing child Views into ViewContainers).
* View can have zero or more ViewPorts. A ViewPort is a marker in the DOM which allows
* View can have zero or more ViewContainers. A ViewContainer is a marker in the DOM which allows
the insertion of child Views.
* Views are created from a ProtoView. A ProtoView is a compiled DOM View which is efficient at
creating Views.
@ -88,7 +88,7 @@ Note:
## Composed View
An important part of an application is to be able to change the DOM structure to render data for the
user. In Angular this is done by inserting child views into the ViewPort.
user. In Angular this is done by inserting child views into the ViewContainer.
Let's start with a View such as:
@ -108,7 +108,7 @@ and
```
<ul> | protoViewA(someContext)
<template></template> | protoViewA(someContext): new ProtoViewPort(protoViewB)
<template></template> | protoViewA(someContext): protoViewB
</ul> | protoViewA(someContext)
```
@ -119,7 +119,7 @@ The next step is to compose these two ProtoViews into an actual view which is re
```
<ul> | viewA(someContext)
<template></template> | viewA(someContext): new Foreach(new ViewPort(protoViewB))
<template></template> | viewA(someContext): new Foreach(new ViewContainer(protoViewB))
</ul> | viewA(someContext)
```
@ -128,11 +128,11 @@ has a reference to `protoViewA`).
*Step3:* As the `Foreach` directive unrolls it asks the `ViewContainerRef` to instantiate `protoViewB` and insert
it after the `ViewPort` anchor. This is repeated for each `person` in `people`. Notice that
it after the `ViewContainer` anchor. This is repeated for each `person` in `people`. Notice that
```
<ul> | viewA(someContext)
<template></template> | viewA(someContext): new Foreach(new ViewPort(protoViewB))
<template></template> | viewA(someContext): new Foreach(new ViewContainer(protoViewB))
<li>{{person}}</li> | viewB0(locals0(someContext))
<li>{{person}}</li> | viewB1(locals0(someContext))
</ul> | viewA(someContext)
@ -145,13 +145,13 @@ delegate any unknown references to the parent context.
```
<ul> | viewA
<template></template> | viewA: new Foreach(new ViewPort(protoViewB))
<template></template> | viewA: new Foreach(new ViewContainer(protoViewB))
<li>Alice</li> | viewB0
<li>Bob</li> | viewB1
</ul> | viewA
```
Each View can have zero or more ViewPorts. By inserting and removing child Views to and from the
Each View can have zero or more ViewContainers. By inserting and removing child Views to and from the
ViewContainers, the application can mutate the DOM structure to any desirable state. A View may contain
individual nodes or a complex DOM structure. The insertion points for the child Views, known as
ViewContainers, contain a DOM element which acts as an anchor. The anchor is either a `template` or
@ -161,7 +161,7 @@ inserted.
## Component Views
A View can also contain Components. Components contain Shadow DOM for encapsulating their internal
rendering state. Unlike ViewPorts which can contain zero or more Views, the Component always contains
rendering state. Unlike ViewContainers which can contain zero or more Views, the Component always contains
exactly one Shadow View.
```

View File

@ -8,8 +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}
* or {@link Viewport}.
* Directive is an abstract concept, instead use concrete directives: {@link Component}, {@link DynamicComponent}, {@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:
@ -55,7 +54,7 @@ import {DEFAULT} from 'angular2/change_detection';
*
* To inject element-specific special objects, declare the constructor parameter as:
* - `element: ElementRef` to obtain a reference to logical element in the view.
* - `viewContainer: ViewContainerRef` to control child template instantiation, for {@link Viewport} directives only
* - `viewContainer: ViewContainerRef` to control child template instantiation, for {@link Decorator} directives only
* - `bindingPropagation: BindingPropagation` to control change detection in a more granular way.
*
* ## Example
@ -188,8 +187,8 @@ import {DEFAULT} from 'angular2/change_detection';
*
* A directive can also query for other child directives. Since parent directives are instantiated before child
* directives, a directive can't simply inject the list of child directives. Instead, the directive
* injects a {@link QueryList}, which updates its contents as children are added, removed, or moved by any
* {@link Viewport} directive such as a `for`, an `if`, or a `switch`.
* injects a {@link QueryList}, which updates its contents as children are added, removed, or moved by a directive
* that uses a {@link ViewContainerRef} such as a `for`, an `if`, or a `switch`.
*
* ```
* @Decorator({ selector: '[my-directive]' })
@ -783,6 +782,98 @@ export class DynamicComponent extends Directive {
* <div tooltip="some text here"></div>
* ```
*
* Decorators can also control the instantiation, destruction, and positioning of inline template elements:
*
* A directive uses a {@link ViewContainerRef} to instantiate, insert, move, and destroy views at runtime.
* The {@link ViewContainerRef} is created as a result of `<template>` element, and represents a location in the current view
* where these actions are performed.
*
* Views are always created as children of the current {@link View}, and as siblings of the `<template>` element. Thus a
* directive in a child view cannot inject the directive that created it.
*
* Since directives that create views via ViewContainers are common in Angular, and using the full `<template>` element syntax is wordy, Angular
* also supports a shorthand notation: `<li *foo="bar">` and `<li template="foo: bar">` are equivalent.
*
* Thus,
*
* ```
* <ul>
* <li *foo="bar" title="text"></li>
* </ul>
* ```
*
* Expands in use to:
*
* ```
* <ul>
* <template [foo]="bar">
* <li title="text"></li>
* </template>
* </ul>
* ```
*
* Notice that although the shorthand places `*foo="bar"` within the `<li>` element, the binding for the directive
* controller is correctly instantiated on the `<template>` element rather than the `<li>` element.
*
*
* ## Example
*
* Let's suppose we want to implement the `unless` behavior, to conditionally include a template.
*
* Here is a simple directive that triggers on an `unless` selector:
*
* ```
* @Directive({
* selector: '[unless]',
* properties: {
* 'unless': 'unless'
* }
* })
* export class Unless {
* viewContainer: ViewContainerRef;
* protoViewRef: ProtoViewRef;
* prevCondition: boolean;
*
* constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef) {
* this.viewContainer = viewContainer;
* this.protoViewRef = protoViewRef;
* this.prevCondition = null;
* }
*
* set unless(newCondition) {
* if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) {
* this.prevCondition = true;
* this.viewContainer.clear();
* } else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) {
* this.prevCondition = false;
* this.viewContainer.create(this.protoViewRef);
* }
* }
* }
* ```
*
* We can then use this `unless` selector in a template:
* ```
* <ul>
* <li *unless="expr"></li>
* </ul>
* ```
*
* Once the directive instantiates the child view, the shorthand notation for the template expands and the result is:
*
* ```
* <ul>
* <template [unless]="exp">
* <li></li>
* </template>
* <li></li>
* </ul>
* ```
*
* Note also that although the `<li></li>` template still exists inside the `<template></template>`, the instantiated
* view occurs on the second `<li></li>` which is a sibling to the `<template>` element.
*
*
* @exportedAs angular2/annotations
*/
export class Decorator extends Directive {
@ -824,127 +915,6 @@ export class Decorator extends Directive {
}
}
/**
* Directive that controls the instantiation, destruction, and positioning of inline template elements.
*
* A viewport directive uses a {@link ViewContainerRef} to instantiate, insert, move, and destroy views at runtime.
* The {@link ViewContainerRef} is created as a result of `<template>` element, and represents a location in the current view
* where these actions are performed.
*
* Views are always created as children of the current {@link View}, and as siblings of the `<template>` element. Thus a
* directive in a child view cannot inject the viewport directive that created it.
*
* Since viewport directives are common in Angular, and using the full `<template>` element syntax is wordy, Angular
* also supports a shorthand notation: `<li *foo="bar">` and `<li template="foo: bar">` are equivalent.
*
* Thus,
*
* ```
* <ul>
* <li *foo="bar" title="text"></li>
* </ul>
* ```
*
* Expands in use to:
*
* ```
* <ul>
* <template [foo]="bar">
* <li title="text"></li>
* </template>
* </ul>
* ```
*
* Notice that although the shorthand places `*foo="bar"` within the `<li>` element, the binding for the `Viewport`
* controller is correctly instantiated on the `<template>` element rather than the `<li>` element.
*
*
* ## Example
*
* Let's suppose we want to implement the `unless` behavior, to conditionally include a template.
*
* Here is a simple viewport directive that triggers on an `unless` selector:
*
* ```
* @Viewport({
* selector: '[unless]',
* properties: {
* 'unless': 'unless'
* }
* })
* export class Unless {
* viewContainer: ViewContainerRef;
* prevCondition: boolean;
*
* constructor(viewContainer: ViewContainerRef) {
* this.viewContainer = viewContainer;
* this.prevCondition = null;
* }
*
* set unless(newCondition) {
* if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) {
* this.prevCondition = true;
* this.viewContainer.clear();
* } else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) {
* this.prevCondition = false;
* this.viewContainer.create();
* }
* }
* }
* ```
*
* We can then use this `unless` selector in a template:
* ```
* <ul>
* <li *unless="expr"></li>
* </ul>
* ```
*
* Once the viewport instantiates the child view, the shorthand notation for the template expands and the result is:
*
* ```
* <ul>
* <template [unless]="exp">
* <li></li>
* </template>
* <li></li>
* </ul>
* ```
*
* Note also that although the `<li></li>` template still exists inside the `<template></template>`, the instantiated
* view occurs on the second `<li></li>` which is a sibling to the `<template>` element.
*
*
* @exportedAs angular2/annotations
*/
export class Viewport extends Directive {
@CONST()
constructor({
selector,
properties,
events,
hostListeners,
hostProperties,
lifecycle
}:{
selector:string,
properties:any,
hostListeners:any,
hostProperties:any,
events:List,
lifecycle:List
}={})
{
super({
selector: selector,
properties: properties,
events: events,
hostListeners: hostListeners,
hostProperties: hostProperties,
lifecycle: lifecycle
});
}
}
//TODO(misko): turn into LifecycleEvent class once we switch to TypeScript;

View File

@ -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, Viewport, DynamicComponent, Decorator} from '../annotations_impl/annotations';
import {Component, DynamicComponent, Decorator} from '../annotations_impl/annotations';
import {AppProtoView} from './view';
import {ProtoViewRef} from './view_ref';
import {DirectiveBinding} from './element_injector';
@ -233,8 +233,6 @@ export class Compiler {
var compileChildren = true;
if ((ann instanceof Component) || (ann instanceof DynamicComponent)) {
renderType = renderApi.DirectiveMetadata.COMPONENT_TYPE;
} else if (ann instanceof Viewport) {
renderType = renderApi.DirectiveMetadata.VIEWPORT_TYPE;
} else if (ann instanceof Decorator) {
renderType = renderApi.DirectiveMetadata.DECORATOR_TYPE;
compileChildren = ann.compileChildren;

View File

@ -87,7 +87,7 @@ export class DynamicComponentLoader {
var binding = this._getBinding(typeOrBinding);
return this._compiler.compileInHost(binding).then(hostProtoViewRef => {
var viewContainer = this._viewManager.getViewContainer(location);
var hostViewRef = viewContainer.create(-1, hostProtoViewRef, injector);
var hostViewRef = viewContainer.create(hostProtoViewRef, viewContainer.length, injector);
var newLocation = new ElementRef(hostViewRef, 0);
var component = this._viewManager.getComponent(newLocation);

View File

@ -7,7 +7,6 @@ import * as viewModule from './view';
export class ElementBinder {
protoElementInjector:eiModule.ProtoElementInjector;
componentDirective:DirectiveBinding;
viewportDirective:DirectiveBinding;
nestedProtoView: viewModule.AppProtoView;
hostListeners:StringMap;
parent:ElementBinder;
@ -15,15 +14,13 @@ export class ElementBinder {
distanceToParent:int;
constructor(
index:int, parent:ElementBinder, distanceToParent: int,
protoElementInjector: eiModule.ProtoElementInjector, componentDirective:DirectiveBinding,
viewportDirective:DirectiveBinding) {
protoElementInjector: eiModule.ProtoElementInjector, componentDirective:DirectiveBinding) {
if (isBlank(index)) {
throw new BaseException('null index not allowed.');
}
this.protoElementInjector = protoElementInjector;
this.componentDirective = componentDirective;
this.viewportDirective = viewportDirective;
this.parent = parent;
this.index = index;
this.distanceToParent = distanceToParent;
@ -40,4 +37,8 @@ export class ElementBinder {
hasDynamicComponent() {
return isPresent(this.componentDirective) && isBlank(this.nestedProtoView);
}
hasEmbeddedProtoView() {
return !isPresent(this.componentDirective) && isPresent(this.nestedProtoView);
}
}

View File

@ -638,7 +638,7 @@ export class ElementInjector extends TreeNode {
}
getViewContainerRef() {
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef(), new ProtoViewRef(this._preBuiltObjects.protoView));
return new ViewContainerRef(this._preBuiltObjects.viewManager, this.getElementRef());
}
getDynamicallyLoadedComponent() {
@ -719,6 +719,9 @@ export class ElementInjector extends TreeNode {
return this.getViewContainerRef();
}
if (dep.key.id === StaticKeys.instance().protoViewId) {
if (isBlank(this._preBuiltObjects.protoView)) {
throw new NoBindingError(dep.key);
}
return new ProtoViewRef(this._preBuiltObjects.protoView);
}
return this._getByKey(dep.key, dep.depth, dep.optional, requestor);

View File

@ -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, Viewport, DynamicComponent} from '../annotations_impl/annotations';
import {Component, DynamicComponent} from '../annotations_impl/annotations';
import * as renderApi from 'angular2/src/render/api';
import {AppProtoView} from './view';
@ -81,8 +81,7 @@ export class ProtoViewFactory {
isPresent(sortedDirectives.componentDirective), parentPeiWithDistance.distance
);
protoElementInjector.attributes = renderElementBinder.readAttributes;
// Viewport directives are treated differently than other element with var- definitions.
if (hasVariables && !isPresent(sortedDirectives.viewportDirective)) {
if (hasVariables) {
protoElementInjector.exportComponent = isPresent(sortedDirectives.componentDirective);
protoElementInjector.exportElement = isBlank(sortedDirectives.componentDirective);
@ -105,8 +104,7 @@ export class ProtoViewFactory {
parent,
renderElementBinder.distanceToParent,
protoElementInjector,
sortedDirectives.componentDirective,
sortedDirectives.viewportDirective
sortedDirectives.componentDirective
);
// text nodes
for (var i=0; i<renderElementBinder.textBindings.length; i++) {
@ -155,14 +153,12 @@ export class ProtoViewFactory {
class SortedDirectives {
componentDirective: DirectiveBinding;
viewportDirective: DirectiveBinding;
renderDirectives: List<renderApi.DirectiveBinder>;
directives: List<DirectiveBinding>;
constructor(renderDirectives, allDirectives) {
this.renderDirectives = [];
this.directives = [];
this.viewportDirective = null;
this.componentDirective = null;
ListWrapper.forEach(renderDirectives, (renderDirectiveBinder) => {
var directiveBinding = allDirectives[renderDirectiveBinder.directiveIndex];
@ -172,9 +168,6 @@ class SortedDirectives {
ListWrapper.insert(this.renderDirectives, 0, renderDirectiveBinder);
ListWrapper.insert(this.directives, 0, directiveBinding);
} else {
if (directiveBinding.annotation instanceof Viewport) {
this.viewportDirective = directiveBinding;
}
ListWrapper.push(this.renderDirectives, renderDirectiveBinder);
ListWrapper.push(this.directives, directiveBinding);
}

View File

@ -7,7 +7,7 @@ import {BaseQueryList} from './base_query_list';
* The directives are kept in depth-first pre-order traversal of the DOM.
*
* The `QueryList` is iterable, therefore it can be used in both javascript code with `for..of` loop as well as in
* template with `*for="of"` viewport.
* template with `*for="of"` directive.
*
* NOTE: In the future this class will implement an `Observable` interface. For now it uses a plain list of observable
* callbacks.

View File

@ -235,9 +235,9 @@ export class AppProtoView {
}
bindElement(parent:ElementBinder, distanceToParent:int, protoElementInjector:ProtoElementInjector,
componentDirective:DirectiveBinding = null, viewportDirective:DirectiveBinding = null):ElementBinder {
componentDirective:DirectiveBinding = null):ElementBinder {
var elBinder = new ElementBinder(this.elementBinders.length, parent, distanceToParent,
protoElementInjector, componentDirective, viewportDirective);
protoElementInjector, componentDirective);
ListWrapper.push(this.elementBinders, elBinder);
return elBinder;
}

View File

@ -10,14 +10,11 @@ import {ViewRef, ProtoViewRef, internalView} from './view_ref';
export class ViewContainerRef {
_viewManager: avmModule.AppViewManager;
_element: ElementRef;
_defaultProtoViewRef: ProtoViewRef;
constructor(viewManager: avmModule.AppViewManager,
element: ElementRef,
defaultProtoViewRef: ProtoViewRef) {
element: ElementRef) {
this._viewManager = viewManager;
this._element = element;
this._defaultProtoViewRef = defaultProtoViewRef;
}
_getViews() {
@ -41,11 +38,8 @@ export class ViewContainerRef {
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
create(atIndex:number=-1, protoViewRef:ProtoViewRef = null, injector:Injector = null): ViewRef {
create(protoViewRef:ProtoViewRef = null, atIndex:number=-1, injector:Injector = null): ViewRef {
if (atIndex == -1) atIndex = this.length;
if (isBlank(protoViewRef)) {
protoViewRef = this._defaultProtoViewRef;
}
return this._viewManager.createViewInContainer(this._element, atIndex, protoViewRef, injector);
}

View File

@ -56,8 +56,8 @@ export class AppViewManagerUtils {
// preBuiltObjects
if (isPresent(elementInjector)) {
var defaultProtoView = isPresent(binder.viewportDirective) ? binder.nestedProtoView : null;
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(viewManager, view, defaultProtoView);
var embeddedProtoView = binder.hasEmbeddedProtoView() ? binder.nestedProtoView : null;
preBuiltObjects[binderIdx] = new eli.PreBuiltObjects(viewManager, view, embeddedProtoView);
}
}

View File

@ -1,6 +1,6 @@
import {Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator} from 'angular2/src/core/annotations_impl/annotations';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ViewRef} from 'angular2/src/core/compiler/view_ref';
import {ViewRef, ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
@ -36,7 +36,7 @@ import {ListWrapper} from 'angular2/src/facade/collection';
*
* @exportedAs angular2/directives
*/
@Viewport({
@Decorator({
selector: '[for][of]',
properties: {
'iterableChanges': 'of | iterableDiff'
@ -44,8 +44,10 @@ import {ListWrapper} from 'angular2/src/facade/collection';
})
export class For {
viewContainer: ViewContainerRef;
constructor(viewContainer:ViewContainerRef) {
protoViewRef: ProtoViewRef;
constructor(viewContainer:ViewContainerRef, protoViewRef: ProtoViewRef) {
this.viewContainer = viewContainer;
this.protoViewRef = protoViewRef;
}
set iterableChanges(changes) {
@ -71,7 +73,7 @@ export class For {
(addedRecord) => ListWrapper.push(insertTuples, new RecordViewTuple(addedRecord, null))
);
For.bulkInsert(insertTuples, this.viewContainer);
For.bulkInsert(insertTuples, this.viewContainer, this.protoViewRef);
for (var i = 0; i < insertTuples.length; i++) {
this.perViewChange(insertTuples[i].view, insertTuples[i].record);
@ -99,14 +101,14 @@ export class For {
return movedTuples;
}
static bulkInsert(tuples, viewContainer) {
static bulkInsert(tuples, viewContainer, protoViewRef) {
tuples.sort((a, b) => a.record.currentIndex - b.record.currentIndex);
for (var i = 0; i < tuples.length; i++) {
var tuple = tuples[i];
if (isPresent(tuple.view)) {
viewContainer.insert(tuple.view, tuple.record.currentIndex);
} else {
tuple.view = viewContainer.create(tuple.record.currentIndex);
tuple.view = viewContainer.create(protoViewRef, tuple.record.currentIndex);
}
}
return tuples;

View File

@ -1,5 +1,6 @@
import {Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator} from 'angular2/src/core/annotations_impl/annotations';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import {isBlank} from 'angular2/src/facade/lang';
/**
@ -25,7 +26,7 @@ import {isBlank} from 'angular2/src/facade/lang';
*
* @exportedAs angular2/directives
*/
@Viewport({
@Decorator({
selector: '[if]',
properties: {
'condition': 'if'
@ -33,17 +34,19 @@ import {isBlank} from 'angular2/src/facade/lang';
})
export class If {
viewContainer: ViewContainerRef;
protoViewRef: ProtoViewRef;
prevCondition: boolean;
constructor(viewContainer: ViewContainerRef) {
constructor(viewContainer: ViewContainerRef, protoViewRef:ProtoViewRef) {
this.viewContainer = viewContainer;
this.prevCondition = null;
this.protoViewRef = protoViewRef;
}
set condition(newCondition /* boolean */) {
if (newCondition && (isBlank(this.prevCondition) || !this.prevCondition)) {
this.prevCondition = true;
this.viewContainer.create();
this.viewContainer.create(this.protoViewRef);
} else if (!newCondition && (isBlank(this.prevCondition) || this.prevCondition)) {
this.prevCondition = false;
this.viewContainer.clear();

View File

@ -1,9 +1,28 @@
import {Decorator, Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator} from 'angular2/src/core/annotations_impl/annotations';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import {isPresent, isBlank, normalizeBlank} from 'angular2/src/facade/lang';
import {ListWrapper, List, MapWrapper, Map} from 'angular2/src/facade/collection';
import {Parent} from 'angular2/src/core/annotations_impl/visibility';
class SwitchView {
_viewContainerRef: ViewContainerRef;
_protoViewRef: ProtoViewRef;
constructor(viewContainerRef: ViewContainerRef, protoViewRef: ProtoViewRef) {
this._protoViewRef = protoViewRef;
this._viewContainerRef = viewContainerRef;
}
create() {
this._viewContainerRef.create(this._protoViewRef);
}
destroy() {
this._viewContainerRef.clear();
}
}
/**
* The `Switch` directive is used to conditionally swap DOM structure on your template based on a
* scope expression.
@ -40,93 +59,94 @@ import {Parent} from 'angular2/src/core/annotations_impl/visibility';
export class Switch {
_switchValue: any;
_useDefault: boolean;
_valueViewContainers: Map;
_activeViewContainers: List<ViewContainerRef>;
_valueViews: Map;
_activeViews: List<SwitchView>;
constructor() {
this._valueViewContainers = MapWrapper.create();
this._activeViewContainers = ListWrapper.create();
this._valueViews = MapWrapper.create();
this._activeViews = ListWrapper.create();
this._useDefault = false;
}
set value(value) {
// Empty the currently active ViewContainers
this._emptyAllActiveViewContainers();
this._emptyAllActiveViews();
// Add the ViewContainers matching the value (with a fallback to default)
this._useDefault = false;
var containers = MapWrapper.get(this._valueViewContainers, value);
if (isBlank(containers)) {
var views = MapWrapper.get(this._valueViews, value);
if (isBlank(views)) {
this._useDefault = true;
containers = normalizeBlank(MapWrapper.get(this._valueViewContainers, _whenDefault));
views = normalizeBlank(MapWrapper.get(this._valueViews, _whenDefault));
}
this._activateViewContainers(containers);
this._activateViews(views);
this._switchValue = value;
}
_onWhenValueChanged(oldWhen, newWhen, viewContainer: ViewContainerRef):void {
this._deregisterViewContainer(oldWhen, viewContainer);
this._registerViewContainer(newWhen, viewContainer);
_onWhenValueChanged(oldWhen, newWhen, view: SwitchView):void {
this._deregisterView(oldWhen, view);
this._registerView(newWhen, view);
if (oldWhen === this._switchValue) {
viewContainer.remove();
ListWrapper.remove(this._activeViewContainers, viewContainer);
view.destroy();
ListWrapper.remove(this._activeViews, view);
} else if (newWhen === this._switchValue) {
if (this._useDefault) {
this._useDefault = false;
this._emptyAllActiveViewContainers();
this._emptyAllActiveViews();
}
viewContainer.create();
ListWrapper.push(this._activeViewContainers, viewContainer);
view.create();
ListWrapper.push(this._activeViews, view);
}
// Switch to default when there is no more active ViewContainers
if (this._activeViewContainers.length === 0 && !this._useDefault) {
if (this._activeViews.length === 0 && !this._useDefault) {
this._useDefault = true;
this._activateViewContainers(MapWrapper.get(this._valueViewContainers, _whenDefault));
this._activateViews(MapWrapper.get(this._valueViews, _whenDefault));
}
}
_emptyAllActiveViewContainers():void {
var activeContainers = this._activeViewContainers;
_emptyAllActiveViews():void {
var activeContainers = this._activeViews;
for (var i = 0; i < activeContainers.length; i++) {
activeContainers[i].remove();
activeContainers[i].destroy();
}
this._activeViewContainers = ListWrapper.create();
this._activeViews = ListWrapper.create();
}
_activateViewContainers(containers: List<ViewContainerRef>):void {
// TODO(vicb): assert(this._activeViewContainers.length === 0);
if (isPresent(containers)) {
for (var i = 0; i < containers.length; i++) {
containers[i].create();
_activateViews(views: List<SwitchView>):void {
// TODO(vicb): assert(this._activeViews.length === 0);
if (isPresent(views)) {
for (var i = 0; i < views.length; i++) {
views[i].create();
}
this._activeViewContainers = containers;
this._activeViews = views;
}
}
_registerViewContainer(value, container: ViewContainerRef): void {
var containers = MapWrapper.get(this._valueViewContainers, value);
if (isBlank(containers)) {
containers = ListWrapper.create();
MapWrapper.set(this._valueViewContainers, value, containers);
_registerView(value, view: SwitchView): void {
var views = MapWrapper.get(this._valueViews, value);
if (isBlank(views)) {
views = ListWrapper.create();
MapWrapper.set(this._valueViews, value, views);
}
ListWrapper.push(containers, container);
ListWrapper.push(views, view);
}
_deregisterViewContainer(value, container: ViewContainerRef):void {
_deregisterView(value, view: SwitchView):void {
// `_whenDefault` is used a marker for non-registered whens
if (value == _whenDefault) return;
var containers = MapWrapper.get(this._valueViewContainers, value);
if (containers.length == 1) {
MapWrapper.delete(this._valueViewContainers, value);
var views = MapWrapper.get(this._valueViews, value);
if (views.length == 1) {
MapWrapper.delete(this._valueViews, value);
} else {
ListWrapper.remove(containers, container);
ListWrapper.remove(views, view);
}
}
}
/**
* Defines a case statement as an expression.
*
@ -144,7 +164,7 @@ export class Switch {
*
* @exportedAs angular2/directives
*/
@Viewport({
@Decorator({
selector: '[switch-when]',
properties: {
'when' : 'switch-when'
@ -153,17 +173,21 @@ export class Switch {
export class SwitchWhen {
_value: any;
_switch: Switch;
_viewContainer: ViewContainerRef;
_view: SwitchView;
constructor(viewContainer: ViewContainerRef, @Parent() sswitch: Switch) {
constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef, @Parent() sswitch: Switch) {
// `_whenDefault` is used as a marker for a not yet initialized value
this._value = _whenDefault;
this._switch = sswitch;
this._viewContainer = viewContainer;
this._view = new SwitchView(viewContainer, protoViewRef);
}
onDestroy() {
this._switch
}
set when(value) {
this._switch._onWhenValueChanged(this._value, value, this._viewContainer);
this._switch._onWhenValueChanged(this._value, value, this._view);
this._value = value;
}
}
@ -182,12 +206,12 @@ export class SwitchWhen {
*
* @exportedAs angular2/directives
*/
@Viewport({
@Decorator({
selector: '[switch-default]'
})
export class SwitchDefault {
constructor(viewContainer: ViewContainerRef, @Parent() sswitch: Switch) {
sswitch._registerViewContainer(_whenDefault, viewContainer);
constructor(viewContainer: ViewContainerRef, protoViewRef: ProtoViewRef, @Parent() sswitch: Switch) {
sswitch._registerView(_whenDefault, new SwitchView(viewContainer, protoViewRef));
}
}

View File

@ -91,7 +91,7 @@ export class ProtoViewDto {
// The view of the component
// Can contain 0 to n views of type #EMBEDDED_VIEW_TYPE
static get COMPONENT_VIEW_TYPE() { return 1; }
// A view that is included via a Viewport directive
// A view that is embedded into another View via a <template> element
// inside of a component view
static get EMBEDDED_VIEW_TYPE() { return 1; }
@ -111,7 +111,6 @@ export class ProtoViewDto {
export class DirectiveMetadata {
static get DECORATOR_TYPE() { return 0; }
static get COMPONENT_TYPE() { return 1; }
static get VIEWPORT_TYPE() { return 2; }
id:any;
selector:string;
compileChildren:boolean;

View File

@ -56,11 +56,7 @@ export class DirectiveParser extends CompileStep {
cssSelector.addAttribute(attrName, attrValue);
});
var viewportDirective;
var componentDirective;
// Note: We assume that the ViewSplitter already did its work, i.e. template directive should
// only be present on <template> elements!
var isTemplateElement = DOM.isTemplateElement(current.element);
this._selectorMatcher.match(cssSelector, (selector, directiveIndex) => {
var elementBinder = current.bindElement();
@ -87,26 +83,12 @@ export class DirectiveParser extends CompileStep {
elementBinder.readAttribute(attrName);
});
}
if (directive.type === DirectiveMetadata.VIEWPORT_TYPE) {
if (!isTemplateElement) {
throw new BaseException(`Viewport directives need to be placed on <template> elements or elements ` +
`with template attribute - check ${current.elementDescription}`);
}
if (isPresent(viewportDirective)) {
throw new BaseException(`Only one viewport directive is allowed per element - check ${current.elementDescription}`);
}
viewportDirective = directive;
} else {
if (isTemplateElement) {
throw new BaseException(`Only template directives are allowed on template elements - check ${current.elementDescription}`);
}
if (directive.type === DirectiveMetadata.COMPONENT_TYPE) {
if (isPresent(componentDirective)) {
throw new BaseException(`Only one component directive is allowed per element - check ${current.elementDescription}`);
}
componentDirective = directive;
elementBinder.setComponentId(directive.id);
if (directive.type === DirectiveMetadata.COMPONENT_TYPE) {
if (isPresent(componentDirective)) {
throw new BaseException(`Only one component directive is allowed per element - check ${current.elementDescription}`);
}
componentDirective = directive;
elementBinder.setComponentId(directive.id);
}
});
}

View File

@ -32,7 +32,7 @@ export class RouterOutlet {
]);
this._viewContainer.clear();
this._viewContainer.create(0, pv, outletInjector);
this._viewContainer.create(pv, 0, outletInjector);
});
}

View File

@ -19,8 +19,6 @@ num _getDirectiveType(String annotationName) {
return DirectiveMetadata.DECORATOR_TYPE;
case 'Component':
return DirectiveMetadata.COMPONENT_TYPE;
case 'Viewport':
return DirectiveMetadata.VIEWPORT_TYPE;
default:
return -1;
}

View File

@ -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, Viewport, Decorator} from 'angular2/src/core/annotations_impl/annotations';
import {Component, DynamicComponent, 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';
@ -150,13 +150,6 @@ export function main() {
});
}));
it('should fill directive.type for viewport directives', inject([AsyncTestCompleter], (async) => {
captureDirective(SomeViewportDirective).then( (renderDir) => {
expect(renderDir.type).toEqual(renderApi.DirectiveMetadata.VIEWPORT_TYPE);
async.done();
});
}));
it('should fill directive.type for decorator directives', inject([AsyncTestCompleter], (async) => {
captureDirective(SomeDecoratorDirective).then( (renderDir) => {
expect(renderDir.type).toEqual(renderApi.DirectiveMetadata.DECORATOR_TYPE);
@ -297,7 +290,7 @@ export function main() {
});
}));
it('should load nested components in viewport', inject([AsyncTestCompleter], (async) => {
it('should load nested components in viewcontainers', inject([AsyncTestCompleter], (async) => {
tplResolver.setView(MainComponent, new View({template: '<div></div>'}));
tplResolver.setView(NestedComponent, new View({template: '<div></div>'}));
var mainProtoView = createProtoView([
@ -451,16 +444,14 @@ function createComponentElementBinder(reader, type) {
var binding = createDirectiveBinding(reader, type);
return new ElementBinder(
0, null, 0,
null, binding,
null
null, binding
);
}
function createViewportElementBinder(nestedProtoView) {
var elBinder = new ElementBinder(
0, null, 0,
null, null,
null
null, null
);
elBinder.nestedProtoView = nestedProtoView;
return elBinder;
@ -502,9 +493,6 @@ class RecursiveComponent {}
@DynamicComponent()
class SomeDynamicComponentDirective {}
@Viewport()
class SomeViewportDirective {}
@Decorator()
class SomeDecoratorDirective {}

View File

@ -2,7 +2,7 @@ import {isPresent} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
import {ddescribe, describe, it, iit, expect, beforeEach} from 'angular2/test_lib';
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
import {Decorator, Component, Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator, Component} from 'angular2/src/core/annotations_impl/annotations';
import {DirectiveMetadata} from 'angular2/src/core/compiler/directive_metadata';
import {Injectable, Injector} from 'angular2/di';
@ -15,9 +15,6 @@ class SomeDecorator {}
@Component({selector: 'someComponent', injectables: [SomeInjectable]})
class SomeComponent {}
@Viewport({selector: 'someViewport'})
class SomeViewport {}
class SomeDirectiveWithoutAnnotation {
}
@ -35,12 +32,6 @@ export function main() {
new DirectiveMetadata(SomeDecorator, new Decorator({selector: 'someDecorator'}), null));
});
it('should read out the Viewport annotation', () => {
var directiveMetadata = reader.read(SomeViewport);
expect(directiveMetadata).toEqual(
new DirectiveMetadata(SomeViewport, new Viewport({selector: 'someViewport'}), null));
});
it('should read out the Component annotation', () => {
var m = reader.read(SomeComponent);
// For some reason `toEqual` fails to compare ResolvedBinding objects.

View File

@ -16,7 +16,7 @@ import {
import {TestBed} from 'angular2/src/test_lib/test_bed';
import {Decorator, Component, Viewport, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator, Component, DynamicComponent} 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';
@ -61,7 +61,7 @@ export function main() {
});
}));
it('should allow to destroy and create them via viewport directives',
it('should allow to destroy and create them via viewcontainer directives',
inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
template: '<div><dynamic-comp #dynamic template="if: ctxBoolProp"></dynamic-comp></div>',

View File

@ -705,6 +705,12 @@ export function main() {
expect(inj.get(NeedsProtoViewRef).protoViewRef).toEqual(new ProtoViewRef(protoView));
});
it("should throw if there is no ProtoViewRef", function () {
expect(
() => injector([NeedsProtoViewRef])
).toThrowError('No provider for ProtoViewRef! (NeedsProtoViewRef -> ProtoViewRef)');
});
});
describe('directive queries', () => {

View File

@ -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, Viewport, DynamicComponent} from 'angular2/src/core/annotations_impl/annotations';
import {Decorator, Component, DynamicComponent} 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';
@ -32,6 +32,7 @@ import {Attribute} from 'angular2/src/core/annotations_impl/di';
import {If} from 'angular2/src/directives/if';
import {ViewContainerRef} from 'angular2/src/core/compiler/view_container_ref';
import {ProtoViewRef} from 'angular2/src/core/compiler/view_ref';
import {Compiler} from 'angular2/src/core/compiler/compiler';
import {ElementRef} from 'angular2/src/core/compiler/element_ref';
@ -522,7 +523,7 @@ export function main() {
})
}));
it('should create a component that injects an @Ancestor through viewport directive', inject([TestBed, AsyncTestCompleter], (tb, async) => {
it('should create a component that injects an @Ancestor through viewcontainer directive', inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
template: `
<some-directive>
@ -865,7 +866,7 @@ class DynamicViewport {
var myService = new MyService();
myService.greeting = 'dynamic greet';
this.done = compiler.compileInHost(ChildCompUsingService).then( (hostPv) => {
vc.create(0, hostPv, inj.createChildFromResolved(Injector.resolve([bind(MyService).toValue(myService)])))
vc.create(hostPv, 0, inj.createChildFromResolved(Injector.resolve([bind(MyService).toValue(myService)])))
});
}
}
@ -1037,13 +1038,13 @@ class ChildComp2 {
}
}
@Viewport({
@Decorator({
selector: '[some-viewport]'
})
class SomeViewport {
constructor(container: ViewContainerRef) {
container.create().setLocal('some-tmpl', 'hello');
container.create().setLocal('some-tmpl', 'again');
constructor(container: ViewContainerRef, protoView:ProtoViewRef) {
container.create(protoView).setLocal('some-tmpl', 'hello');
container.create(protoView).setLocal('some-tmpl', 'again');
}
}

View File

@ -44,8 +44,8 @@ export function main() {
return new AppView(null, createProtoView(), MapWrapper.create());
}
function createViewContainer(defaultProtoView = null) {
return new ViewContainerRef(viewManager, location, defaultProtoView);
function createViewContainer() {
return new ViewContainerRef(viewManager, location);
}
beforeEach( () => {

View File

@ -60,12 +60,12 @@ export function main() {
}
function createEmptyElBinder() {
return new ElementBinder(0, null, 0, null, null, null);
return new ElementBinder(0, null, 0, null, null);
}
function createComponentElBinder(nestedProtoView = null) {
var binding = createDirectiveBinding(SomeComponent);
var binder = new ElementBinder(0, null, 0, null, binding, null);
var binder = new ElementBinder(0, null, 0, null, binding);
binder.nestedProtoView = nestedProtoView;
return binder;
}

View File

@ -45,12 +45,12 @@ export function main() {
}
function createEmptyElBinder() {
return new ElementBinder(0, null, 0, null, null, null);
return new ElementBinder(0, null, 0, null, null);
}
function createComponentElBinder(nestedProtoView = null) {
var binding = createDirectiveBinding(SomeComponent);
var binder = new ElementBinder(0, null, 0, null, binding, null);
var binder = new ElementBinder(0, null, 0, null, binding);
binder.nestedProtoView = nestedProtoView;
return binder;
}

View File

@ -17,8 +17,6 @@ export function main() {
annotatedDirectives = [
someComponent,
someComponent2,
someViewport,
someViewport2,
someDecorator,
someDecoratorIgnoringChildren,
decoratorWithMultipleAttrs,
@ -153,27 +151,6 @@ export function main() {
expect(eventBinding.source.source).toEqual('doItGlobal()');
});
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
describe('viewport directives', () => {
it('should not allow multiple viewport directives on the same element', () => {
expect( () => {
process(
el('<template some-vp some-vp2></template>')
);
}).toThrowError('Only one viewport directive is allowed per element - check '
+ (assertionsEnabled() ? '<template some-vp some-vp2>' : 'null'));
});
it('should not allow viewport directives on non <template> elements', () => {
expect( () => {
process(
el('<div some-vp></div>')
);
}).toThrowError('Viewport directives need to be placed on <template> elements or elements with template attribute - check '
+ (assertionsEnabled() ? '<div some-vp>' : 'null'));
});
});
//TODO: assertions should be enabled when running tests: https://github.com/angular/angular/issues/1340
describe('component directives', () => {
it('should save the component id', () => {
@ -231,18 +208,6 @@ var someComponent2 = new DirectiveMetadata({
type: DirectiveMetadata.COMPONENT_TYPE
});
var someViewport = new DirectiveMetadata({
selector: '[some-vp]',
id: 'someViewport',
type: DirectiveMetadata.VIEWPORT_TYPE
});
var someViewport2 = new DirectiveMetadata({
selector: '[some-vp2]',
id: 'someViewport2',
type: DirectiveMetadata.VIEWPORT_TYPE
});
var someDecorator = new DirectiveMetadata({
selector: '[some-decor]',
type: DirectiveMetadata.DECORATOR_TYPE

View File

@ -43,7 +43,7 @@ export function main() {
['properties', MapWrapper.createFromPairs([['propKey', 'propVal']])],
['readAttributes', ['readTest1', 'readTest2']],
['selector', 'testSelector'],
['type', DirectiveMetadata.VIEWPORT_TYPE]
['type', DirectiveMetadata.DECORATOR_TYPE]
]);
var meta = directiveMetadataFromMap(map);
expect(meta.compileChildren).toEqual(false);
@ -56,7 +56,7 @@ export function main() {
MapWrapper.createFromPairs([['propKey', 'propVal']]));
expect(meta.readAttributes).toEqual(['readTest1', 'readTest2']);
expect(meta.selector).toEqual('testSelector');
expect(meta.type).toEqual(DirectiveMetadata.VIEWPORT_TYPE);
expect(meta.type).toEqual(DirectiveMetadata.DECORATOR_TYPE);
});
});
}

View File

@ -405,7 +405,7 @@ var multipleContentTagsComponent = new DirectiveMetadata({
var manualViewportDirective = new DirectiveMetadata({
selector: '[manual]',
id: 'manual',
type: DirectiveMetadata.VIEWPORT_TYPE
type: DirectiveMetadata.DECORATOR_TYPE
});
var outerWithIndirectNestedComponent = new DirectiveMetadata({
@ -441,7 +441,7 @@ var conditionalContentComponent = new DirectiveMetadata({
var autoViewportDirective = new DirectiveMetadata({
selector: '[auto]',
id: '[auto]',
type: DirectiveMetadata.VIEWPORT_TYPE
type: DirectiveMetadata.DECORATOR_TYPE
});
var tabGroupComponent = new DirectiveMetadata({

View File

@ -16,7 +16,7 @@ import {
import {TestBed} from 'angular2/test';
import {Injector, bind} from 'angular2/di';
import {Component, Viewport} from 'angular2/src/core/annotations_impl/annotations';
import {Component} from 'angular2/src/core/annotations_impl/annotations';
import {View} from 'angular2/src/core/annotations_impl/view';
import {RootRouter} from 'angular2/src/router/router';

View File

@ -9,7 +9,7 @@ import {
import {IMPLEMENTS} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
import {RootRouter, Viewport} from 'angular2/src/router/router';
import {RootRouter} from 'angular2/src/router/router';
import {Pipeline} from 'angular2/src/router/pipeline';
import {RouterOutlet} from 'angular2/src/router/router_outlet';

View File

@ -1,4 +1,4 @@
import {bootstrap, Component, Viewport, View, ViewContainerRef, Compiler, Decorator} from 'angular2/angular2';
import {bootstrap, Component, View, ViewContainerRef, Compiler, Decorator} from 'angular2/angular2';
import {LifeCycle} from 'angular2/src/core/life_cycle/life_cycle';
import {reflector} from 'angular2/src/reflection/reflection';

View File

@ -7,11 +7,10 @@ import {Component, Decorator} from 'angular2/src/core/annotations_impl/annotatio
import {View} from 'angular2/src/core/annotations_impl/view';
// Angular 2.0 supports 3 basic types of directives:
// Angular 2.0 supports 2 basic types of directives:
// - Component - the basic building blocks of Angular 2.0 apps. Backed by
// ShadowDom.(http://www.html5rocks.com/en/tutorials/webcomponents/shadowdom/)
// - Decorator - add behavior to existing elements.
// - Viewport - allow for stamping out of a html template (not in this demo).
// @Component is AtScript syntax to annotate the HelloCmp class as an Angular
// 2.0 component.
@ -46,8 +45,8 @@ export class HelloCmp {
}
}
// Decorators are light-weight. They don't allow for templates, or new
// expression contexts (use @Component or @Viewport for those needs).
// Decorators are light-weight. They don't allow new
// expression contexts (use @Component for those needs).
@Decorator({
selector: '[red]'
})