Академический Документы
Профессиональный Документы
Культура Документы
0: Life of a Template
Hello Anonymous! How are you? Just want to let you know that we are doing a really rough
draft of this document right now. So, it might not be coherent or even correct until we are done :)
Just letting you know...
API
When a developer creates a component...
1. Developer authors the component code
2. Pass component Type with Metadata to compiler
3. Compiler returns ProtoView (via Promise)
4. Create ViewFactory from ProtoView (maybe)
5. Use ProtoView/ViewFactory to instantiate Views
Compiler Internals
Component Instantiation
class Item {
text:string;
constructor(text) {
this.text = text;
}
}
@Component({
selector: 'todos',
template: new TemplateConfig({
url: 'todos.html',
uses: [core.directives]
})
})
class Todos {
todos:List<Item>;
constructor() {
this.todos = [new Item('Take over the World')];
}
}
<ul>
<li [ng-repeat|item]="todos">
${item.text}
</li>
</ul>
<span>There are ${todos.length} todos.</span>
Notice that the compilation is on the component rather than on the DOM element. This is
because the DOM element is not sufficient by itself to define the UI. The key missing parts is the
configuration of which directives are active in the current template. This is information is present
in the Component annotation.
The second thing to notice, is that the result of compilation is a promise rather than a ready to
use ProtoView. This is because components may load other components and loading is async.
This is in contrast to current implementation where the compilation is synchronous but the
runtime (instantiation of components) is asynchronous.
The compiler's job is to look for directives in the template and to create ProtoView. The
ProtoView is a serializable description of the template, its configuration and its directives. To
achieve the compilation the compiler needs to configure which directives should be active for a
given component. This information is defined in the components @Component annotation.
Compilation Process
<ul>
<li [ng-repeat|item]="todos">
${item.text}
</li>
</ul>
<span>There are ${todos.length} todos.</span>
new ProtoView({
type: LocalContext,
protoElementInjectors: [
new ProtoElementInjector({
textNodes: [ 0 ]
})
],
protoWatchGroup: new ProtoWatchGroup({
'item.text': 0
})
});
new View(
documentFragment: ...
elementInjectors: [],
textNodes: [ #text ]
)
new ProtoView({
type: Todos,
protoElementInjectors: [
new ProtoElementInjector({
directives: [ NgRepeat, liProtoView ]
}),
new ProtoElementInjector({
textNodes: [ 0 ]
})
],
protoWatchGroup: new ProtoWatchGroup({
'todos': new DirectiveToken(0, 0, setterFn),
// setterFn(o, v) => o.collection = v;
"'There are ' + todos.length + 'todos.'": 0
})
})
new View({
documentFragment: ...
elementInjectors: [
new ElementInjector( <template> )
],
textNodes: [ #text ]
})
Walker
class Walker {
selector: Selector;
protoElementInjectors:Array<ProtoElementInjectors>;
protoWatchGroup:ProtoWatchGroup
textNodeIndex:int;
visit(element:Element) {
// We processe the child text nodes and hoist their bindings
var childElements:Array<Element> = [];
var protoElementInjector = null;
element.forEach((node, index) => {
switch (node.nodeType) {
case Document.ELEMENT_TYPE:
childElements.push(node);
break;
case Document.TEXT_TYPE;
var interpolation = interpolate(node.text);
if (interpolation) {
protoElementInjector =
ensureProtoElementInjector(protoElementInjector);
protoElementInjector.textNode.push(index);
protoWatchGroup.watch(
interpolation, this.textNodeIndex++);
}
break;
}
});
setupProtoElementInjector(childElements:Array<Element>,
directives:Array<TypeDirectiveTuple>)
{
directives.forEach(tuple => {
if (tuple.annotation is Component) {
// recurse into the components template
}
protoElementInjector.addDirective(tuple.type);
});
childElements.forEach(visit);
}
ensureProtoElementInjector(protoElementInjector) {
if (protoElementInjector == null) {
protoElementInjector = new ProtoElementInjector();
this.protoElementInjectors.push(proto);
}
return protoElementInjector;
}
}
@Template({
selector: '[ng-repeat]',
//observe: {'ng-repeat': 'onCollectionChange'}
})
class NgRepeat {
constructor(viewFactor:ViewFactor, viewPort:ViewPort) {
}
@Observe('ng-repeat')
onCollectionChange(record:ChangeRecord) {
record.forEachNew((e) => {
var view:View = viewFactory.new();
viewPort.add(view);
});
record.forEachDelete((e) => {
view.destroy();
});
}
}
<app>
#ShadowRoot
<tab>
#ShadowRoot
*
<pane>
#ShadowRoot
*
</pane>
<tab>