2016-08-03 9 views
5

Ich kenne die Lehrbuch Regeln auf diese <div *ngFor="let foo of foobars">{{foo.stuff}}</div> wird <template ngFor let-foo="$implicit" [ngForOf]="foobars"><div>...</div></template>. Meine Frage ist zweifach:Angular2: Wie ist ngfor erweitert

  • WIE?
  • Was muss ich tun, um diesen Mechanismus ("Mikrosyntax") selbst zu nutzen?

Ie wiederum <div *myDirective="item">{{item.stuff}}</div> in <template myDirective let-item="$implicit"><div>{{item.stuff}}</div></template>?

Da ich den Quellcode von ngFor von oben nach unten gelesen habe, kann ich nur annehmen, dass diese dunkle Magie irgendwo im Compiler ist, ich habe den eckigen GitHub auf und ab, aber ich kann meinen Finger nicht darauf legen. Hilfe!

Antwort

11

Ja, alle Magie im Compiler passiert.

Lassen Sie uns diese Vorlage nehmen:

<div *ngFor="let foo of foobars">{{foo}}</div> 

Zuerst wird auf die folgende umgewandelt werden:

<div template="ngFor let foo of foobars>{{foo}}</div> 

Und dann:

<template ngFor let-foo [ngForOf]="foobars"><div>{{foo}}</div></template> 

In Angular2 rc.4 es sieht aus wie dies enter image description here

Zuerst wird ast Baumknoten (Abstract Syntax-Baum-Knoten) erzeugt und dann alles geht wie in den TemplateParseVisitor.visitElement (https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L284) speziell am Boden (https://github.com/angular/angular/blob/2.0.0-rc.4/modules/%40angular/compiler/src/template_parser.ts#L394)

if (hasInlineTemplates) { 
    var templateCssSelector = createElementCssSelector(TEMPLATE_ELEMENT, templateMatchableAttrs); 
    var templateDirectiveMetas = this._parseDirectives(this.selectorMatcher, templateCssSelector); 
    var templateDirectiveAsts = this._createDirectiveAsts(
     true, element.name, templateDirectiveMetas, templateElementOrDirectiveProps, [], 
     element.sourceSpan, []); 
    var templateElementProps: BoundElementPropertyAst[] = this._createElementPropertyAsts(
     element.name, templateElementOrDirectiveProps, templateDirectiveAsts); 
    this._assertNoComponentsNorElementBindingsOnTemplate(
     templateDirectiveAsts, templateElementProps, element.sourceSpan); 
    var templateProviderContext = new ProviderElementContext(
     this.providerViewContext, parent.providerContext, parent.isTemplateElement, 
     templateDirectiveAsts, [], [], element.sourceSpan); 
    templateProviderContext.afterElement(); 

    parsedElement = new EmbeddedTemplateAst(
     [], [], [], templateElementVars, templateProviderContext.transformedDirectiveAsts, 
     templateProviderContext.transformProviders, 
     templateProviderContext.transformedHasViewContainer, [parsedElement], ngContentIndex, 
     element.sourceSpan); 
} 
return parsedElement; 

Diese Methode gibt EmbeddedTemplateAst. Es ist das gleiche wie:

<template ngFor let-foo [ngForOf]="foobars"><div>{{foo}}</div></template> 

Wenn Sie aktivieren möchten:

<div *myDirective="item">{{item.stuff}}</div> 

in

<template myDirective let-item><div>{{item.stuff}}</div></template> 

dann müssen Sie die folgende Syntax verwenden:

<div *myDirective="let item">{{item.stuff}}</div> 

Aber In diesem Fall werden Sie den Kontext nicht weitergeben. Ihre benutzerdefinierte Struktur Richtlinie könnte wie folgt aussehen:

@Directive({ 
    selector: '[myDirective]' 
}) 
export class MyDirective { 
    constructor(
    private _viewContainer: ViewContainerRef, 
    private _templateRef: TemplateRef<any>) {} 

    @Input() set myDirective(prop: Object) { 
    this._viewContainer.clear(); 
    this._viewContainer.createEmbeddedView(this._templateRef, prop); <== pass context 
    } 
} 

Und Sie können es gerne verwenden:

<div *myDirective="item">{{item.stuff}}</div> 

       || 
       \/ 

<div template="myDirective:item">{{item.stuff}}</div> 

       || 
       \/ 

<template [myDirective]="item"> 
    <div>{{item.stuff}}</div> 
</template> 

Ich hoffe, dies wird Ihnen helfen zu verstehen, wie strukturelle Richtlinien arbeiten.

Update:

Mal sehen, wie es funktioniert (plunker)

*dir="let foo v foobars" => [dirV]="foobars" 

enter image description here

So können Sie die folgende Anweisung schreiben:

@Directive({ 
    selector: '[dir]' 
}) 
export class MyDirective { 
    @Input() 
    dirV: any; 

    @Input() 
    dirK: any; 

    ngAfterViewInit() { 
    console.log(this.dirV, this.dirK); 
    } 
} 

@Component({ 
    selector: 'my-app', 
    template: `<h1>Angular 2 Systemjs start</h1> 
    <div *dir="let foo v foobars k arr">{ foo }</div> 
    `, 
    directives: [MyDirective] 
}) 
export class AppComponent { 
    foobars = [1, 2, 3]; 
    arr = [3,4,5] 
} 

Hier ist die entsprechende Plunker

Siehe auch

Live-Beispiel finden Sie hier https://alexzuza.github.io/enjoy-ng-parser/

+0

Ja !!! Ich habe gestern den passierenden Kontext herausgefunden, und ich fand die TEMPLATE_PREFIX-Sache im Compiler, also kam ich irgendwie dazu, aber Ihre Bestätigung bestätigt mir. – TDaver

+0

Ich verstehe jetzt, wie es '* dir =" let foo "' in 'template dir let-foo' verwandelt, aber woher weiß es,'ofobars' in' [ngForOf] = "foobars" '' zu verwandeln? Woher kommt das ngFor-Präfix? Woher weiß es, welches in ein Let zu verwandeln ist und welches mit dem Namen der Direktive für eine zweite Direktive vorangestellt wird? – TDaver

+0

Ich bin mir nicht sicher, aber scheint '* dir =" let foo von foobars "' wird sein '[dirOf] =" toolbars " – yurzui

0

*ngFor, *ngIf, ... sind strukturelle Richtlinien.

Entweder es auf einem <template> Element anwenden oder es das Präfix mit einem *

https://angular.io/docs/ts/latest/guide/structural-directives.html#!#unless

import { Directive, Input } from '@angular/core'; 
import { TemplateRef, ViewContainerRef } from '@angular/core'; 
@Directive({ selector: '[myUnless]' }) 
export class UnlessDirective { 
    constructor(
    private templateRef: TemplateRef<any>, 
    private viewContainer: ViewContainerRef 
    ) { } 
    @Input() set myUnless(condition: boolean) { 
    if (!condition) { 
     this.viewContainer.createEmbeddedView(this.templateRef); 
    } else { 
     this.viewContainer.clear(); 
    } 
    } 
} 
+0

Ja, das wusste ich :) Ich fragte nach den fortgeschritteneren Möglichkeiten, Dinge zu tun. – TDaver

Verwandte Themen