2016-05-27 12 views
2

Ich benötige Hilfe bezüglich eines extern geänderten DOM innerhalb einer Angular2 RC1 Web App. Das Szenario ist einfach: Ich habe eine Komponente mit einer entsprechenden Vorlage zu tun haben, die mit einer ID wie diesesAngular2, ZoneJS und extern geändertes DOM

<div id="my-svg-canvas"></div> 

Die typescripted Komponente ein leeres div enthält, hat eine ngOnInit Methode, die eine Funktion aus einer einfachen JS-Datei löst die enthalten ist via script-tag in der index.html. Diese Funktion rendert ein SVG in das oben aufgeführte "div" -Tag. Das SVG enthält einige a-Elemente mit On-Click-Direktiven, die auf mehrere Methoden in meiner Komponente verweisen.

Das funktionierte damals in Angular1 nach dem Aufruf von $ scope. $ Apply() nachdem das SVG vollständig geschrieben wurde. Jetzt werden in Angular2 die entsprechenden Methoden in meiner Komponente nicht ausgelöst.

Ich weiß, dass ZoneJS jetzt für die Erkennung von Änderungen im DOM verantwortlich ist. Ich hatte gehofft, dass dies automatisch für das gesamte DOM erledigt wird, das in einer von Angular verwalteten Komponente gerendert wird. Nächster Versuch war NgZone in meiner Komponente zu injizieren und explizit die Rendering-Funktion darin, wie folgt ausführen:

ngOnInit() { 
    this.ngZone.run(() => {renderSVG(this.myData, "my-svg-canvas");}) 
} 

kein Erfolg - entweder/Außerdem registrierte ich eine MutationObserver (siehe diesen Thread: Angular2 Directive: How to detect DOM changes), da das Problem ist mir ein bisschen ähnlich vorgekommen. Es hat aber auch nicht gefeuert.

Ich habe keine Ahnung, wo zu suchen, keine Fehlermeldung zu klammern an: - ???

Hinweis: Es war notwendig, "on-click" anstelle von "(click)" zu verwenden, da das SVG-Rendering-Framework die Angabe ungültiger Attribute verweigerte. Offensichtlich sind Attribute, die mit einer Klammer beginnen, für HTML gut, aber nicht für XML. Dies sollte jedoch nicht das Problem sein, da beide Richtlinien perfekt austauschbar sind.

PS:

Die genannte Rendering-Methode Verwendung des SVG.js Rahmen macht und sieht wie folgt aus:

function renderSVG(dataParam, elementIdParam) { 
    draw = SVG(elementIdParam).spof(); 
    initAndPaint(draw, dataParam); 
    return draw; 
} 

und den von der SVG.js erzeugten Tag lib

<a id="SvgjsA1033" on-click="showVal('W1')" class="union"> 

Wenn ich den generierten SVG-Code in meine Vorlage einfüge, funktioniert alles einwandfrei.

Antwort

2

Ich glaube nicht, dass Angular Ihren dynamisch hinzugefügten HTML analysieren wird (siehe Angular2 - catch/subscribe to (click) event in dynamically added HTML).

Nachdem Sie also renderSVG() aufgerufen haben, müssen Sie wahrscheinlich das DOM durchlaufen und die neu hinzugefügten a Elemente finden und dann manuell einen Ereignishandler für jeden hinzufügen und später entfernen.

Siehe Dynamically add event listener in Angular 2.

Für einen komplizierteren Ansatz siehe Equivalent of $compile in Angular 2.

+0

Die Lösung in den ersten Links gibt mir wirklich Gänsehaut :-) Ich gab der DynamicLoaderComponent eine Chance und es funktioniert tatsächlich, obwohl es sich im Mittelalter wie eine Zeitreise im Vergleich zum Einzeiler in Angular1 fühlt . Fairerweise haben wir es mit der RC zu tun, aber eine bessere Lösung sollte vorgestellt werden. – Matt

+0

Danke! Ich habe die Implementierung zu Ihrem Beitrag hinzugefügt und als "akzeptiert" – Matt

+0

@ user3802631 gekennzeichnet, stimme ich voll und ganz zu. Wir brauchen etwas einfacher als die DynamicLoaderComponent. Ihre Bearbeitung wurde abgelehnt. Ich schlage vor, Sie fügen es als separate Antwort hinzu. –

1

ich Ihren Code in die ngAfterViewInit Hook-Methode Ihrer Komponente bewegen würde:

<div #mySvgCanvas"></div> 

und

@ViewChild('mySvgCanvas') 
mySvgCanvasElt: ElementRef; 

ngAfterViewInit() { 
    var elt = this.mySvgCanvasElt.nativeElement; 
:

ngAfterViewInit() { 
    this.ngZone.run(() => {renderSVG(this.myData, "my-svg-canvas");}) 
} 

Darüber hinaus sollten Sie Ihr DOM-Element mit dem ViewChild Dekorateur Referenz

Ich denke nicht, dass die Verwendung von Zonen explizit ich s hier erforderlich ...

+0

Danke Thierry für die schnelle Antwort. Ich habe getan, wie du gesagt hast, immer noch nicht funktioniert. Ich habe die Viewchild-Eigenschaft überprüft, nachdem das Rendering passiert ist und das ganze SVG da ist, was gut ist. Außerdem habe ich ein weiteres Viewchild neben der Zeichenfläche hinzugefügt: ein -Tag mit einer On-Click-Direktive, genau wie im SVG, um zu sehen, ob oder wie sich ihre ElementRef.nativeElemittens unterscheiden. Das einzelne -nativeelement hat ein __zone_symbol__eventtasks Array angehängt, alle Tags in der SVG haben nicht. Ich habe das SVG-Rendering innerhalb ngZone und einmal ohne ausgeführt. Kein Unterschied: -/ – Matt

+0

Können Sie einen Auszug Ihrer 'renderSvg' Methode zur Verfügung stellen? Nur um zu sehen, wie es aussieht ... –

+1

Natürlich. Bitte beachten Sie den PS-Abschnitt, den ich am Ende der Frage hinzugefügt habe. – Matt

1

Mark Rajcoks Link (siehe "Für einen komplizierteren Ansatz") zu einer Lösung mit DynamicLoaderComponent in der angenommenen Antwort funktioniert. Als Abschluss für diesen Thread ist das meine Implementierung:

constructor(private loader: DynamicComponentLoader, private injector:Injector) {} 

ngAfterViewInit() { 
    let tournamentCanvas = document.createElement("canvas"); 
    renderKOTournamentSVG(this.tournament, tournamentCanvas); 

    @Component({ 
    selector: 'canvas-component', 
    template: tournamentCanvas.outerHTML)} 
    class CanvasComponent {} 

    this.loader.loadAsRoot(CanvasComponent, "canvas-component", this.injector); 
} 
Verwandte Themen