Ошибка загрузки значка из реестра Material Icon с тегом » не найден»

#angular #svg #angular-material #angular-httpclient

#angular #svg #angular-material #angular-httpclient

Вопрос:

Я пытаюсь реализовать кнопки с пользовательскими значками SVG, используя Angular Material 7.2 и Angular 7.2.11. Я не столкнулся с какими-либо проблемами при использовании стандартного шрифта значка материала. Однако пользовательские значки просто приводят к появлению «Значка ошибки при извлечении: <svg> тег не найден» на консоли.

Я копался в коде в @angular/material/esm2015/icon.js и обнаружили, что _fetchUrl (), похоже, получает SVG, но тело объекта HttpResponse пустое, несмотря на фактический ответ, содержащий SVG, как подтверждено Firefox. Заголовки в объекте HttpResponse содержат правильную длину содержимого.

При вставке URL-адреса, сообщенного объектом HttpResponse, в браузер отображается правильный SVG.

_fetchUrl() использует параметр ‘text’ responseType для HttpClient::get(), что должно быть нормально, насколько я могу судить, несмотря на указание в ответе content-type: image/svg xml . На всякий случай я переименовал SVG и дал ему расширение ‘txt’. Последующий ответ имел text/plain тип содержимого, но тело HttpResponse по-прежнему было пустым.

Удаление реестра значков материалов из уравнения и простая get() попытка приводит к той же проблеме. Запрос успешно завершен, SVG отправлен, но HttpResponse имеет пустое тело.

Модуль приложения:

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

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

Компонент приложения:

 @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}`));
  }
}
  

Компонентный HTML:

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

Тестируйте файлы SVG:

 <?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>
  

Вывод на консоль:

 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
  

Запрос / ответ:

 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>
  

Ответ №1:

Наконец-то удалось отследить проблему до HTTP-перехватчика в проекте. Это приводило к удалению тела ответа.

Комментарии:

1. Здравствуйте, я сталкиваюсь с такой же проблемой прямо сейчас. Вы также выяснили, как предотвратить его удаление из тела? Поскольку мне нужен перехватчик, чтобы исправить SSR для пользовательских svg-файлов в Material-UI MatIconRegistry .

2. В моем случае это было нечто подобное, http-перехватчик заменял URL-адрес для вызова конечной точки сервера. Решается с помощью условия if, подобного path === assests ? _not replace_ : _replace_

Ответ №2:

Вы можете следовать этому фрагменту кода для каждого добавления настраиваемых значков материалов в реестр материалов. Значки Я поддерживаю перечисляемый список значков и использую методы загрузки значков. Шаг 1: Сначала создайте IconService.

 import { Injectable } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { environment } from 'src/environments/environment';
import { Icons } from '../../enums/icons.enum';

@Injectable({
  providedIn: 'root'
})
export class IconService {

  baseURL: string = environment.baseURL;
  constructor(
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer
  ) { }

  public registerIcons(): void {
    this.loadIcons(Object.values(Icons), this.baseURL   'assets/svg/icons');
  }

  private loadIcons(iconKeys: string[], iconUrl: string): void {
    iconKeys.forEach(key => {
      debugger;
      this.matIconRegistry.addSvgIcon(key, this.domSanitizer.bypassSecurityTrustResourceUrl(`${iconUrl}/${key}.svg`));
    });
  }

}

  

Шаг 2: Внедрите службу в свой app.module.ts в разделе provider

 
@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent
  ],
  imports: [
    AppRoutes,
    NgbModule,
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    BrowserAnimationsModule,
    MatMenuModule,
    MatSidenavModule,
    MatIconModule,
    MatTooltipModule,
    ToastrModule.forRoot(),
  ],
  providers: [ ToastrService , CookieService, ErrorService, HttpService, StorageService, IconService
   ],
  bootstrap: [AppComponent]
})
export class AppModule { }
  

Шаг 3: Внедрите службу значков в файл конструктора app.component.ts и вызовите методы registerIcons

 import { Component } from '@angular/core';
import { IconService } from './core/services/icon/icon.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'

})
export class AppComponent {

  constructor(private iconService: IconService) {
    this.iconService.registerIcons();
  }

}

  

Ответ №3:

 this.domSanitizer.bypassSecurityTrustResourceUrl('./assets/svg/test.svg'));
  

Вы видите разницу?

Комментарии:

1. Да, я должен был упомянуть, что пробовал разные пути, хотя, как я уже упоминал, он отлично находит SVG и отвечает на запрос правильным SVG, что подтверждено с помощью сетевого анализа Firefox. Проблема возникает после того, как он получает SVG и пытается его проанализировать. Однако, просто ради моего здравомыслия, я пошел дальше и попробовал этот измененный путь еще раз, и это не помогло.