Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
236 views
in Technique[技术] by (71.8m points)

angular - Why dynamically created (SVG) rect component only appears in DOM and not in view?

I have created a component: SimpleVertice. In DOM it is a simple rect element with bound logic. It has an input parameter called vertice that represents an (x,y) based point. It is a very basic example so it will just position the element properly by x and y.

I have also created a container for these elements in app.component.html. It is a simple 400x400 sized SVG element.

I wanted to create SimpleVertice components dynamically from code but the result was very strange. Angular created the elements in DOM and I also had access to the reference of them, but in the view they have not rendered. Maybe I missed something so my question is how can I achive this with angular components properly?

Container SVG:

<svg with="400" height="400"
    style="width: 400px; height: 400px; position: fixed; top: 0; left: 0; border: 1px solid red">

    <ng-container #vc></ng-container> <!-- It does not -->
    <rect simplevertice [vertice]="{x: 100, y: 100}"></rect> <!-- It works properly -->
</svg>

Dynamic component:

const factory = this.componentFactoryResolver.resolveComponentFactory(
  SimpleVerticeComponent
);
const vertCompRef = this.vc.createComponent<SimpleVerticeComponent>(
  factory
);
vertCompRef.instance.vertice = { x: 50, y: 50 };

SimpleVertice:

@Component({
  selector: "rect[simplevertice]",
  templateUrl: "./simple-vertice.component.html",
  styleUrls: ["./simple-vertice.component.css"],
  encapsulation: ViewEncapsulation.None,
  host: {
    "[attr.stroke-width]": "1",
    "[attr.width]": "4",
    "[attr.height]": "4",
    "[attr.x]": "vertice.x-2",
    "[attr.y]": "vertice.y-2"
  }
})
export class SimpleVerticeComponent implements OnInit {
  @Input() vertice: { x: number; y: number } = { x: 0, y: 0 };

  constructor() {}

  ngOnInit() {}
}

//css
//rect[simplevertice] {
//  fill: red;
//}

Result: enter image description here

Full example here: https://stackblitz.com/edit/angular-ivy-rehyfq?file=src/app/app.component.ts

(Sorry for the misspelled vertex :/) Thanks for your time and answer!

question from:https://stackoverflow.com/questions/65945698/why-dynamically-created-svg-rect-component-only-appears-in-dom-and-not-in-view

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem was with the namespace! Angular generate nodes with http://www.w3.org/1999/xhtml namespace but svg nodes should have http://www.w3.org/2000/svg as value.

So after I realised this I have found that it is a bug in Angular. I also have the link for this issue if someone wants to check: https://github.com/angular/angular/issues/10404

The recommended workaround (not for all versions of Angular :/) here:

    const factory = this.componentFactoryResolver.resolveComponentFactory(
      SimpleVerticeComponent
    );
    let rectNode = document.createElementNS(
      "http://www.w3.org/2000/svg",
      "rect"
    );
    const vertCompRef = factory.create(this.injector, [], rectNode);
    vertCompRef.instance.elRef.nativeElement.setAttribute("simpleVertice", "");
    this.vc.insert(vertCompRef.hostView);
    vertCompRef.instance.vertice = { x: 50, y: 50 };

I know it is a little bit hacky but good to know you can achive this as well even with these Angular limitations.

Full example here: https://stackblitz.com/edit/angular-ivy-7myf4x?file=src%2Fapp%2Fapp.component.ts


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...