Home > Back-end >  Angular way of doing javascript getById code
Angular way of doing javascript getById code

Time:02-11

I'm working on a migration project from AngularJS to Angular8

where I came across this code

// get the pattern from SVG document and set the stroke color
 var patternElt = $scope.svgDocument.find("#striped");
 patternElt.css("fill", color);
 // apply the striped class to the element
 element.css("fill", "url(#striped)");
 $(zoneClassSelector, element).css("fill", "url(#striped)");

what the above code does is when an element is clicked, it gets a pattern element from an svg file (below) and adds a fill color to it, and then applies it on the clicked DOM element :

<defs>
    <pattern id="striped" 
        width="8" height="8" 
        patternUnits="userSpaceOnUse"
        patternTransform="rotate(45)">
        <rect width="4" height="8" transform="translate(0,0)"></rect>
    </pattern>
</defs>

In my case in Typescript code I have the following

click($event: MouseEvent) {

let clickedEl = $event.target;
// check if clicked element is not an svg element 
if (clickedEl instanceof SVGPolygonElement || clickedEl instanceof SVGPathElement || clickedEl instanceof SVGGElement) {
  this.renderer.setAttribute(clickedEl, "style", "fill:url(#striped);");
}

}

Note: the SVG file is loaded with its path (no SVG xml in the component view to reference)

How could I get the striped pattern element using Typscript to add a fill color to it before pass it to the renderer setAttribute

CodePudding user response:

You can try using document.querySelector()

public fillColor(): void {
  const rectElement: SVGRectElement = document.querySelector('#striped') as SVGRectElement;
  rectElement.style.fill = 'red';
}
<svg (click)="fillColor()">
  <defs>
    <pattern id="Pattern" width=".25" height=".25">
      <rect x="0" y="0" id="striped" width="50" height="50" />
    </pattern>
  </defs>
  <rect fill="url(#Pattern)" width="200" height="200" />
</svg>

CodePudding user response:

Any DOM element reference can be obtained through the ViewChild attribute

so in your case, you would have the following:

<pattern #MyReference
    id="striped" 
    width="8" height="8" 
    patternUnits="userSpaceOnUse"
    patternTransform="rotate(45)">
    <rect width="4" height="8" transform="translate(0,0)"></rect>
</pattern>

Then in your class you would reference the DOM object

@ViewChild('MyReference', { static: false })
MyElem: ElementRef;

You can now do any DOM manipulation utilising this reference, along with the Core Renderer2 library (import into your constructor private renderer: Renderer2).

If however you have a dynamic list of SVG elements loaded, and are looking for a way to get "within" the clicked elements DOM - I would go the route of creating a custom Component that "each" of these then initalises, and have the on click, and element references within here. This way each component has a singular build pattern, and you don't have to do any parent/sibling DOM traversing.

e.g. (very basic, you'll know what inputs you require)

<ng-container *ngFor="let svg of list">
    <my-custom-component [inputs]="svg"></my-custom-component>
</ng-container>

Then using the above method, each component on click only has the single pattern element reference to manipulate without direct DOM traversing. It will also keep your on click method quite precise and you don't need to check what was clicked, since only this component will trigger it (no need for global mouse events)

EDIT 1 In seeing the comments, I believe what you could be after is utilising global css variables. For example, you can do the following in the XML:

enter image description here

Then set your root class to show its selected (on click), for example:

<svg  >
    <use xlink:href="#" href="#" />
</svg>

Then all you do is change your fill color via CSS to what you are wanting it to show i.e.

.selected pattern
{
   --fill-color:"#123456"
}

If none of these are suitable, might have to update the question a little for understanding sorry

  • Related