ng-inline-svg icon indicating copy to clipboard operation
ng-inline-svg copied to clipboard

Should support being provided with a SVG as a string

Open espeandr opened this issue 6 years ago • 10 comments

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request

Current behavior

Currently the directive only support beeing provided a SVG through a URL.

Wanted behaviour

I would like to be able to pass the directive a SVG as a string, like so:

@Component({
  selector: 'demo',
  template: `
    <div [inlineSVG]="svgAsString" [isSVGString]="true"></div>
  `
})
export class DemoComponent {
    public svgAsString = `
      <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
        <circle cx="5.899" cy="8.979" r="2.792"/>
      </svg>`;
  
}

What is the motivation / use case for changing the behavior?

By beeing able to provide SVG as a string, developers can handle the fetching of the SVG themselves. My concrete need is to be able to implement a retry mechanism on the fetching of the SVG.

espeandr avatar May 18 '18 14:05 espeandr

Maybe proving an svg like this would keep the API clean:

[inlineSVG]="data:image/svg+xml,[...]"

zygimantas avatar May 20 '18 16:05 zygimantas

I'm not sure if it's really practical as a library user to provide data URIs. That said, I'm not entirely sure why you would readily have an SVG as a string either. It'd make more sense to me if you had the element itself, but @espeandr can chime in.

arkon avatar May 20 '18 17:05 arkon

I did express the motivation behind this issue in the original issue's body, but I'll try to rephrase:

This directive handles fetching of a SVG by using the HttpClient in the SVGCacheService, based on a URL a user provides like so: this._http.get(absUrl, {responseType: 'text'}). The response of such a request would be a SVG as a string. I would like to handle this fetching myself, so that I can implement a mechanism that in cases of error responses retries the GET-request until a valid response is achieved, e.g. by using the rxjs retryWhen operator. When I have the response, I can then provide this string to this directive. I think this makes this directive more flexible by giving users an option of handling querying for the SVG themselves, not relying on the mechanics as implemented in SVGCacheService

espeandr avatar May 20 '18 20:05 espeandr

If that's the case, wouldn't it make more sense to be able to specify something to use for fetching the SVG, which the directive can use in place of the default SVGCacheService?

arkon avatar May 20 '18 22:05 arkon

I see your point, but wouldn't this service that replaces SVGCacheService also have to implement SVGCacheService's setBaseUrl and getAbsoluteUrl, unless more substantial refactoring is done? Another solution could be to provide a class that replaces SVGCacheService use of the HttpClient during registration of the module.

In my case, such a class would retry failing requests, as well as alerting users that a issue has occurred by displaying a toast through another dependent service. However, I might not want this "retry and alert" mechanism for all SVGs I insert using this directive. To solve this, one could provide the directive with such a service as a input instead, or have a flag deciding whether to use the default "SVGFetcher (HttpClient) or a custom service that was provided during module registration. I think this is feasible, but I also think it would complicate the API quite a bit. Also, I'm not really sure coupling services for fetching, retrying and alerting into this directive for inlining SVGs is the cleanest approach either.

I might have misunderstood your suggestion, or there might be a better way to do what you suggested @arkon, but based on what I laid out above, I still think allowing users to provide the directive with a SVG as a string directly is the simplest and most flexible way to give consumers of the directive control of the fetching of a SVG themselves.

espeandr avatar May 21 '18 13:05 espeandr

From my implementation point of view, it'd just be a matter of providing the user a way of passing in an implementer of a SVGFetcher interface, which has a single function: getSVG(id: string): Observable<SVGElement>. SVGCacheService would be the default implementation, where it handles id being a relative or absolute URL.

Maybe it'd be possible to provide both the current SVGCacheService and another one that handles an SVG as a string as well.

arkon avatar May 21 '18 15:05 arkon

I have a case where the svg definition is inside a database (CLOB). I would simply take this string and render it inside my component (caches are working fine). It would be a nice feature!

andreclinio avatar Oct 16 '18 13:10 andreclinio

In my case this is usefull because I need to load a few hundred svgs and doing a single HTTP Request for them is not really nice. Fetching them all at the same time in a json document would be much nicer.

juliusstoerrle avatar Nov 12 '18 14:11 juliusstoerrle

I'm currently really struggling with finding a good svg injector, which supports an svg string. Is there currently a workaround for using a string based svg resource with inlineSVG ?

NiklasPor avatar Aug 10 '19 18:08 NiklasPor

It is also something I would find useful as i'm storing some SVGs inside indexedDB for offline use. The SVGFetcher implementation would be inconvenient in my case because I have more than one type of svg and they come from different sources.

mcarriere avatar Jan 20 '21 19:01 mcarriere