问题
I need some help concerning an externally changed DOM within an Angular2 RC1 web app. The scenario is simple: I do have a component with an according template that contains an empty div with an ID like this
<div id="my-svg-canvas"></div>
The typescripted component has an ngOnInit method that triggers a function from a plain JS file that is included via script-tag in the index.html. That function renders an SVG into the above listed "div" tag. The SVG contains some a-elements with on-click directives that reference several methods in my component.
That worked fine back then in Angular1 after calling $scope.$apply() after the SVG was completely written. Now, in Angular2 the respective methods in my component are not triggered.
I know, that ZoneJS is now responsible for detecting changes in the DOM. I was hoping that this is done automatically for the whole DOM rendered inside an Angular-managed component. Next try was to inject NgZone in my component and explicitly run the rendering function therein, like this:
ngOnInit() {
this.ngZone.run(() => {renderSVG(this.myData, "my-svg-canvas");})
}
No success either :-/ Moreover, I registered a MutationObserver (see this thread: Angular2 Directive: How to detect DOM changes), since the problem occurred a little similar to me. It hasn't fired either, though.
I have no clue where to look for, no error message to cling to :-???
Note: It was necessary to use "on-click" instead of "(click)" since the SVG rendering framework refused to set invalid attributes. Obviously attributes starting with a bracket are fine for HTML, but not for XML. However, this should not be the problem, since both directives are perfectly exchangable.
PS:
The rendering method called makes use of the SVG.js framework and looks like this:
function renderSVG(dataParam, elementIdParam) {
draw = SVG(elementIdParam).spof();
initAndPaint(draw, dataParam);
return draw;
}
And the tag generated by the SVG.js lib
<a id="SvgjsA1033" on-click="showVal('W1')" class="union">
When I paste the generated SVG code into my template, everything works fine.
回答1:
I don't think Angular is going to parse your dynamically added HTML (see Angular2 - catch/subscribe to (click) event in dynamically added HTML).
So, after you call renderSVG()
, you'll probably need to traverse the DOM and find the newly added a
elements and then manually add (and later remove) an event handler for each one.
See Dynamically add event listener in Angular 2.
For a more involved approach, see Equivalent of $compile in Angular 2.
回答2:
I would move your code into the ngAfterViewInit
hook method of your component:
ngAfterViewInit() {
this.ngZone.run(() => {renderSVG(this.myData, "my-svg-canvas");})
}
Moreover you should reference your DOM element using the ViewChild
decorator:
<div #mySvgCanvas"></div>
and
@ViewChild('mySvgCanvas')
mySvgCanvasElt: ElementRef;
ngAfterViewInit() {
var elt = this.mySvgCanvasElt.nativeElement;
I don't think that using zones explicitly is required here...
回答3:
Mark Rajcok's link (see "For a more involved approach") to a solution using DynamicLoaderComponent
in the accepted answer works. As a closure for this thread this is my implementation:
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);
}
来源:https://stackoverflow.com/questions/37485672/angular2-zonejs-and-externally-changed-dom