Использование Renderer в Angular 4

Я понимаю, почему лучше использовать средство визуализации вместо прямого управления DOM в проектах Angular2. Тем не менее, я удалил, очистил кеш, переустановил Node, Typescript и Angular -CLI несколько раз, и я все еще получаю сообщение об ошибке при попытке вставить Renderer.

import { Injectable, Renderer2 } from '@angular/core';
constructor(private renderer: Renderer2) {}

__ zone_symbol__message: "Нет провайдера для Renderer2!"

__ zone_symbol__stack: "Ошибка" в Error.ZoneAwareError

Есть ли у кого-нибудь идеи, что я делаю неправильно?

Ответ 1

В соответствии с вашими ввозами

import { Injectable, Renderer2 } from '@angular/core'

Я подозреваю, что вы пытаетесь ввести Renderer2 в свой класс обслуживания. Это не сработает. Вы не можете вводить Renderer2 в сервисе. Он должен работать на компоненты и службы, которые предоставляются внутри компонента.

Мы можем взглянуть на исходный код https://github.com/angular/angular/blob/4.0.1/packages/core/src/view/provider.ts#L363-L373

while (view) {
  if (elDef) {
    switch (tokenKey) {
      case RendererV1TokenKey: {
        const compView = findCompView(view, elDef, allowPrivateServices);
        return createRendererV1(compView);
      }
      case Renderer2TokenKey: {
        const compView = findCompView(view, elDef, allowPrivateServices);
        return compView.renderer;
      }

он проверяет только внутри дерева инжектора элементов. И нет других мест, где этот токен может быть предоставлен

Итак, вы должны передать Renderer2 из компонента в службу, когда вы вызываете какой-либо метод обслуживания https://github.com/angular/angular/issues/17824#issuecomment-311986129

или вы можете предоставить услугу в компоненте

@Injectable()
export class Service {
  constructor(private r: Renderer2) {}
}
@Component({
  selector: 'my-app',
  templateUrl: `./app.component.html`,
  providers: [Service]
})
export class AppComponent { 
  constructor(private service: Service) {}
}

Ответ 2

Вы не можете вводить Renderer2, но мы можем запустить RendererFactory2, чтобы получить экземпляр Renderer2 внутри @Injectable(). Например, существует способ, которым Angular используется внутри веб-мастеров, например.

Я решил проблему с кодом ниже:

import { Renderer2, RendererFactory2 } from '@angular/core';

@Injectable()
class Service {
    private renderer: Renderer2;

    constructor(rendererFactory: RendererFactory2) {
        this.renderer = rendererFactory.createRenderer(null, null);
    }
}

Параметры метода RendererFactory2.createRenderer:

  • hostElement с типом any
  • type с типом RendererType2|null

Вы можете видеть, что параметры (null, null) находятся здесь: https://github.com/angular/angular/blob/e3140ae888ac4037a5f119efaec7b1eaf8726286/packages/core/src/render/api.ts#L129