【问题标题】:Where does a custom pipe instance live? How can the component code access the custom pipe instance used in its HTML?自定义管道实例在哪里?组件代码如何访问其 HTML 中使用的自定义管道实例?
【发布时间】:2018-02-08 17:29:09
【问题描述】:

我在组件的 HTML 部分中使用了一个自定义管道。它在模块中声明:

  declarations: [  I18nPipe ],

我希望能够从组件代码中调用它的方法(不是transform 方法)。

我希望管道实例存在于依赖注入上下文中的某个位置,以便我可以抓住它。但是我错了。如果我将它注入到组件的构造函数中(例如任何普通服务):

  constructor(private i18nPipe: I18nPipe)  

然后我得到一个错误:没有提供者。所以我将它包含在同一模块的providers 部分:

  providers: [ I18nPipe ]

然后我将可以在组件代码中访问它,但我的自定义管道会有 两个 实例。

  1. providers 创建,在 DI 上下文中可用。在构造函数中注入时我会得到这个实例,所以我将在我的组件代码中使用这个实例。

  2. 在 HTML 中使用的实例。它在哪里生活?我想在我的组件代码中访问这个实例,而不是“提供”的那个;如何获得?

【问题讨论】:

  • 声明在模板中可用,提供者通过 DI。为什么它们是单独的实例很重要?如果管道有状态,最好将它移到别处。除了变换还有什么方法?需要更多上下文才能给出有用的答案。
  • 我有一种方法可以尝试配置一点管道。而不是输入参数(需要出现在 html 模板中的所有管道外观中),我想尝试从代码中设置配置参数。例如设置语言。当然,保持状态并注入管道的服务会更干净,我只是尝试缩短它,看看是否可能。并发现了这一点——这是我没有预料到的。无论如何:组件也存在于声明和 DI 树中。为什么管道不行?一般来说是为了更好地理解角度。
  • “组件也出现在声明和 DI 树中” - 我认为您也不能注入组件或指令。跨度>
  • 考虑使用服务代替您的配置信息。然后任何所需的组件或您的管道都可以引用该服务。

标签: angular angular2-di angular2-custom-pipes


【解决方案1】:

每个 Angular 组件都被编译到带有节点的视图中。管道是节点类型之一。除了父组件和在组件的宿主元素上定义的指令之外,您不能注入视图节点。

假设您有以下组件模板:

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

您将拥有以下视图节点:

PipeElement
HTMLDivElement
HTMLTextElement

然后在变更检测期间,Angular 会遍历每个节点并执行变更检测特定操作 - dom 更新、绑定更新或transform 方法调用。

如果您愿意,您可以通过 View 实例(不是公共 API)访问管道实例,如下所示:

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();
    })
  }

但这仅用于教育目的。您不想在生产中使用这种方法。

这里有一些文章可以帮助你理解:

【讨论】:

  • 谢谢马克西姆。很有用。就在我的进场方向上。还有一个问题:如果我在 HTML 中多次使用管道,会有几个管道节点但只有一个管道实例?我检查了一下,只有一个管道实例。 OBS:在我的 Angular 4 中,cd 上没有 _view,因此他们可能限制了对内部内容的访问。正如你所说,无论如何这只是为了理解。
  • @Dacian,不客气。应该有与您使用管道一样多的实例。管道实例是有状态的,例如,async 管道持有 rxjs 订阅,不能在所有管道之间共享。你是怎么检查的?此外,_view 应该可用。它没有暴露在 ChangeDetectorRef 接口上,但 ChangeDetectorRef 只是底层视图的包装器
  • 我还期望每次使用一个实例。我现在重新测试,确实我现在看到了几个实例(我在构造函数中随机生成一个 id 并打印它 - 所以每个创建的实例都有一个 id)。这非常重要:框架每次使用创建一个实例 - 应在管道文档 IMO 中说明。就像在 Spring 框架中一样:当一个 bean 范围 = 原型明确说明一个 bean 时(我不能停止认为 Spring 作为我知道依赖 DI 的主要框架 - 框架创建的所有内容都可以在 DI 上下文中使用 - 在Angular 不是这样)。
  • 哇!!!多么美妙的发现:)纯管道——只有一个实例(我在组件 HTML 模板中有多种用法)。不纯管道 - 每次使用一个实例(在 HTML 模板中一个接一个地使用)。
  • 谢谢,这里是answer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-09
  • 2017-10-11
  • 2022-10-16
  • 1970-01-01
  • 1970-01-01
  • 2016-06-18
  • 2017-08-15
相关资源
最近更新 更多