angularsvgangular-materialangular-httpclient

Loading icon from Material Icon Registry errors out with "<svg> tag not found"


I am trying to implement buttons that have custom SVG icons using Angular Material 7.2 and Angular 7.2.11. I have not encountered any issues using the standard Material icon font. However custom icons just result in "Error retrieving icon: <svg> tag not found" on the console.

I have been digging through the code in @angular/material/esm2015/icon.js and have found that _fetchUrl() appears to be receiving the SVG, but the body of the HttpResponse object is empty despite the ACTUAL response containing the SVG as verified by Firefox. The headers in the HttpResponse object include a correct content length.

Pasting the URL reported by the HttpResponse object into a browser renders the correct SVG.

_fetchUrl() is using the 'text' responseType option to HttpClient::get(), which should be fine, as far as I can tell, despite the response specifying content-type: image/svg+xml. Just to be sure, I renamed the SVG and gave it a 'txt' extension. The subsequent response had the text/plain content type, but the body of the HttpResponse was still empty.

Removing the Material icon registry from the equation and just attempting a simple get() yields the same issue. The request completes successfully, the SVG is sent, but the HttpResponse has an empty body.

App module:

import { HttpClientModule, ... } from '@angular/common/http';
import {
 ...
 MatIconModule,
 ...
} from '@angular/material';

@NgModule({
 ...
 imports: [
  ...
  HttpClientModule,
  MatIconModule
  ...
 ],
 ...
})

App component:

@Component({
 ...
})
export class AppComponent {
  constructor(private router: Router, private matIconRegistry: MatIconRegistry, private domSanitizer: DomSanitizer, private http: HttpClient, ...)
  {
    this.matIconRegistry.addSvgIcon('test_icon',
      this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/svg/test.svg'));

    http.get('/assets/svg/test.svg', { responseType: 'text' })    .subscribe(svg => console.log(`Response: ${svg}`));
  }
}

Component HTML:

<button mat-icon-button>
  <mat-icon svgIcon="test_icon"></mat-icon>
</button>

Test SVG Files:

<?xml version="1.0" encoding="UTF-8" ?>
<svg width="64" height="64" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <rect x="0" y="0" width="64" height="64" style="fill:rgb(0,0,0,0)" />
</svg>
<svg>Test</svg>

Console Output:

Request to access cookie or storage on “https://fonts.googleapis.com/icon?family=Material+Icons” was blocked because we are blocking all third-party storage access requests and content blocking is enabled. calendar

Angular is running in the development mode. Call enableProdMode() to enable the production mode. core.js:21273

Error retrieving icon: <svg> tag not found icon.js:867:81

Request / Response:

GET /assets/svg/test.svg HTTP/1.1

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Content-Type: image/svg+xml; charset=UTF-8
Content-Length: 219
ETag: W/"d9-8SqOE9sCdf/cpMgr8wAdHVFXV+g"
Date: Tue, 02 Apr 2019 00:36:12 GMT
Connection: keep-alive
<?xml version="1.0" encoding="utf-8" ?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
  <rect x="0" y="0" width="32" height="32" style="fill:rgb(0,0,0,0)" />
</svg>

Solution

  • Finally tracked the issue down to an HTTP interceptor in the project. It was wiping out the body of the response.