Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Renderer in Angular 4

I understand why it's better to use renderer instead of directly manipulating the DOM in Angular2 projects. However, I have uninstalled, clear cache, reinstalled Node, Typescript and the Angular-CLI several times and I still get an error when trying to inject the Renderer.

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

__zone_symbol__message: "No provider for Renderer2!"

__zone_symbol__stack:"Error↵ at Error.ZoneAwareError

Does anyone have any ideas what I am doing wrong?

like image 784
Michael_Cloudbusting Avatar asked Mar 28 '17 13:03

Michael_Cloudbusting


People also ask

What is the use of Renderer in Angular?

Use a custom renderer to bypass Angular's templating and make custom UI changes that can't be expressed declaratively. For example if you need to set a property or an attribute whose name is not statically known, use the setProperty() or setAttribute() method.

When should I use Renderer 2?

The Renderer2 allows us to manipulate the DOM elements, without accessing the DOM directly. It provides a layer of abstraction between the DOM element and the component code. Using Renderer2 we can create an element, add a text node to it, append child element using the appendchild method., etc.

Is Renderer2 deprecated?

The Renderer class has been marked as deprecated since Angular version 4. This section provides guidance on migrating from this deprecated API to the newer Renderer2 API and what it means for your app.

What is Renderer service?

The Renderer class is a built-in service that provides an abstraction for UI rendering manipulations. For example, you need to set the focus on an input element, so you may be tempted to do something like: This works fine.


2 Answers

Update:

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

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

See more on this here: https://github.com/angular/angular/issues/17824#issuecomment-351961146

Previous version:

According to your imports

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

i suspect that you're trying to inject Renderer2 in your service class. It won't work. You can't inject Renderer2 in service. It should work for components and services that are provided within component.

We can take a look at source code 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;
      }

it checks only within element injector tree. And there are no other places when this token can be provided

So you have to pass Renderer2 from component to service when you're calling some service method https://github.com/angular/angular/issues/17824#issuecomment-311986129

or you can provide service within component

@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) {}
}
like image 93
yurzui Avatar answered Oct 05 '22 01:10

yurzui


You cannot inject Renderer2, but we can run RendererFactory2 to get Renderer2 instance inside @Injectable() service. There is the way which Angular using internally in webworkers, for example.

I've solved the problem with the code below:

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

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

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

Parameters of RendererFactory2.createRenderer method are:

  • hostElement with type any
  • type with type RendererType2|null

You can see that (null, null) parameters are here: https://github.com/angular/angular/blob/e3140ae888ac4037a5f119efaec7b1eaf8726286/packages/core/src/render/api.ts#L129

like image 23
Eugene Gavrilov Avatar answered Oct 05 '22 00:10

Eugene Gavrilov