Angular2, ZoneJS and externally changed DOM

做~自己de王妃 提交于 2019-12-10 22:33:51

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!