angularangular2-diangular2-custom-pipes

Where does a custom pipe instance live? How can the component code access the custom pipe instance used in its HTML?


I have a custom pipe I use in the HTML part of a component. It is declared in the module:

  declarations: [  I18nPipe ],

I want to be able to call a method on it from the component code (not the transform method).

I was hoping that the pipe instance is living somewhere in the dependency injection context so that I can grab it. But I was wrong. If I inject it in the constructor of the component (like any normal service, for example):

  constructor(private i18nPipe: I18nPipe)  

then I got an error: no providers. So I include it in the providers section of the same module:

  providers: [ I18nPipe ]

then I will have access to it in the component code but there will be two instances of my custom pipe.

  1. created by providers, available in DI context. I will get this instance when injected in the constructor, so I will work with this instance in my component code.

  2. the instance that is used in the HTML. Where does it live? I want access to this instance in my component code, not to the "provided" one; how can I obtain it?


Solution

  • Every Angular component is compiled into the View with nodes. And pipes are one of the nodes types. And you can't inject view nodes except for parent components and directives defined on the host element of the component.

    Suppose you have the following template for a component:

    <div>{{3|mypipe}}</div>
    

    You will have the following view nodes:

    PipeElement
    HTMLDivElement
    HTMLTextElement
    

    Then during change detection Angular runs through each node and performs change detection specific action - dom update, bindings update or transform method call.

    If you wanted, you could access the instance of the pipe through the View instance (which is not public API) like this:

    class I18nPipe {
       sayHello() {}
    }
    
    class ComponentWithPipe {
    
      constructor(cd: ChangeDetectorRef) {
        setTimeout(() => {
          const pipeNode = cd._view.nodes.find((n) => {
            return n.instance && n.instance instanceof I18nPipe
          });
          const pipeInstance = pipeNode.instance;
          pipeInstance.sayHello();
        })
      }
    

    But this is for educational purposes only. You don't want to use this approach in production.

    Here are some of the articles that will help you understand: