如何使用服务的输入/输出动态创建组件实例并将其单独注入到 DOM 中?

2024-02-05

在 Angular 2 中创建动态组件时,我found https://stackoverflow.com/questions/36325212/angular-2-dynamic-tabs-with-user-click-chosen-components/36325468#36325468 out https://www.lucidchart.com/techblog/2016/07/19/building-angular-2-components-on-the-fly-a-dialog-box-example/这个过程需要ViewContainerRef为了将新创建的组件添加到 DOM 中。

顺便说一下@Input and @Output对于那些动态创建的组件,我在上面的第二个链接中找到了答案,here https://codedump.io/share/kQakwDKNu0iG/1/passing-input-while-creating-angular-2-component-dynamically-using-componentresolver.

但是,如果我要创建一个名为shape.service包含返回不同形状组件的函数@Input like bgColor,我不知道这个服务如何在不指定 DOM 位置的情况下创建一个组件,以及容器组件如何接收这个返回的组件(可能它的类型是ComponentRef) 来自服务并将其注入到指定的 DOM 容器组件中。

例如,一个服务包含一个方法:

getCircle(bgColor:string): ComponentRef<Circle> {
    let circleFactory = componentFactoryResolver.resolveComponentFactory(CircleComponent);
    let circleCompRef = this.viewContainerRef.createComponent(circleFactory);
    circleCompRef.instance.bgColor = bgColor;

    return circleCompRef;
}

第一个问题出现在这里,我该如何制作this.viewContainerRef暂时没有指出哪里?我进口的原因ViewContainerRef就是动态创建组件。

第二个问题是容器组件收到特定输入后componentRef从服务中,它将如何注入到其 DOM 中?

UPDATE:我认为我上面的问题不够具体。我现在的情况是:

  1. 父组件调用服务并获取 componentRef/s,
  2. 创建一个包含 componentRef 和其他一些数据的对象,并将这些创建的对象存储到数组中
  3. 将其传递给其子级@Input,
  4. 并让每个子级将 componentRef 注入到其 DOM 中,并以其他方式使用对象中的其余数据。

这意味着服务调用组件不知道这些 componentRef 将被注入到哪里。简而言之,我需要可以随时随地注入到我想要的独立组件对象。

我已经多次阅读 rumTimeCompiler 解决方案,但我并不真正了解它是如何工作的。与使用 viewContainerRef 创建组件相比,工作量似乎太多了。如果我找不到其他解决方案,我会进一步研究......


如果像我这样的人现在仍在寻找简单明了的解决方案 - 就在这里。我从@angular/cdk 那里得到的https://github.com/angular/components/tree/master/src/cdk https://github.com/angular/components/tree/master/src/cdk并做了一个简单的服务。

import {
    Injectable,
    ApplicationRef,
    ComponentFactoryResolver,
    ComponentRef,
    Injector,
    EmbeddedViewRef
} from '@angular/core';

export type ComponentType<T> = new (...args: any[]) => T;

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

    constructor(
        private _appRef: ApplicationRef,
        private _resolver: ComponentFactoryResolver,
        private _injector: Injector
    ) { }

    private _components: ComponentRef<any>[] = [];

    add<T>(
        component: ComponentType<T> | ComponentRef<T>,
        element?: Element | string
    ): ComponentRef<T> {
        const componentRef = component instanceof ComponentRef
            ? component
            : this._resolver.resolveComponentFactory(component).create(this._injector);
        this._appRef.attachView(componentRef.hostView);
        if (typeof element === 'string') {
            element = document.querySelector(element);
        }
        if (!element) {
            element = document.body;
        }
        element.appendChild(
            (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0] as HTMLElement
        );
        this._components.push(componentRef);
        return componentRef;
    }

    remove(dialog: number | ComponentRef<any>): boolean {
        let componentRef;
        if (typeof dialog === 'number' && this._components.length > dialog)  {
            componentRef = this._components.splice(dialog, 1)[0];
        }
        else {
            for (const cr of this._components) {
                if (cr === dialog) {
                    componentRef = cr;
                }
            }
        }
        if (componentRef) {
            this._remove(componentRef);
            return true;
        }
        return false;
    }

    private _remove(componentRef: ComponentRef<any>) {
        this._appRef.detachView(componentRef.hostView);
        componentRef.destroy();
    }

    clear() {
        while (this._components.length > 0) {
            this._remove(this._components.pop());
        }
    }

    getIndex(componentRef: ComponentRef<any>): number {
        return this._components.indexOf(componentRef);
    }

}

您可以将 ComponentClass 或 ComponentRef 传递给addElement 或任何指向任何 DOM 元素的 querySelector 字符串,您想要将组件作为第二个参数附加到其中(或者什么都没有,那么它假设您想要附加到主体)。

const cr = this._service.add(MyComponent); // will create MyComponent and attach it to document.body or
const cr = this._service.add(MyComponent, this.someElement); // to attach to Element stored in this.someElement or
const cr = this._service.add(MyComponent, 'body div.my-class > div.my-other-div'); // to search for that element and attach to it
const crIndex = this._service.getIndex(cr);
cr.instance.myInputProperty = 42;
cr.instance.myOutputEmitter.subscribe(
    () => {
        // do something then for example remove this component
        this._service.remove(cr);
    }
);
this._service.remove(crIndex); // remove by index or
this._service.remove(cr); // remove by reference or
this._service.clear(); // remove all dynamically created components

附:别忘了将动态组件添加到entryComponents: [] of @NgModule

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用服务的输入/输出动态创建组件实例并将其单独注入到 DOM 中? 的相关文章

随机推荐

  • 关于模板专业化和继承的良好实践

    模板专业化不考虑继承层次结构 例如 如果我专门设计一个模板Base并实例化它Derived 不会选择专业 参见下面的代码 1 这可能是一个主要障碍 因为它有时会导致违反里氏替换原则 例如 在工作时这个问题 https stackoverfl
  • python:安装anaconda后,如何导入pandas

    我已经安装了蟒蛇 现在当我尝试跑步时 import pandas as pd 我收到以下错误 Traceback most recent call last File
  • Python 中的词法分析、标记化和解析资源

    人们可以向我指出有关使用 Python 进行词法分析 解析和标记化的资源吗 我正在对一个开源项目进行一些黑客攻击 hotwire http www hotwire shell org 并想对代码进行一些更改lexes http code g
  • Poco C++ 库和 Win32 GUI 集成

    有人曾经在 Win32 GUI 应用程序中使用过 Poco C 库吗 在 PocoFoundation 库中 UnWindows h 头文件中的许多 undef 禁止使用重要的 API 如 CreateWindows LoadLibrary
  • 从tensorflow.js神经网络获取权重

    我有这个顺序模型 this model tf sequential this model add tf layers dense units 16 useBias true inputDim 7 input this model add t
  • 使用 XMLInputFormat 在 hadoop 中解析 xml 时不执行我的 hadoop 映射器类

    我是 hadoop 新手 使用 Hadoop 2 6 0 版本并尝试解析复杂的 XML 经过一段时间的搜索 我了解到 对于 XML 解析 我们需要编写自定义的 InputFormat 即 mahout 的 XMLInputFormat 我也
  • 如何将图像拖放到 HTML5 Canvas 上?

    我修改了一个页面 可以将图像拖放到画布上 它可以做我想要的一切 除了一个 我尝试了多种方法 包括脚本 例如 Kinetic 和 Raphael 我仍然认为这可能是可行的方法 但已经死了 一旦图像被放下 我就无法将其在画布上拖动到新位置 fu
  • 使用 PDFBox 从字符串中删除非法字符

    当我尝试向 PDF 中写入非法字符时 我显然遇到了异常 例如 contentStream showText some illegal characters java lang IllegalArgumentException U 000A
  • Python pandas 相当于替换

    在R中 有一个相当有用的replace功能 本质上 它在数据帧的给定列中进行有条件的重新分配 它可以这样使用 replace df column df column 1 Type 1 在 pandas 中实现相同目标的好方法是什么 我应该使
  • 仅通过命令行在 Windows 上运行 CMake 生成的 INSTALL.vcxproj?

    我有一个 C 程序 正在尝试在 AppVeyor 上构建和部署 因此 我没有可用的 GUI 工具 我的项目的依赖项均使用 CMake 作为其构建系统 并且 CMake 默认情况下 在 Windows 上生成 Visual Studio 项目
  • Java - 同时将两个表达式分配给一个变量

    我刚刚学完 Java 第一年 我一直在查看 JDK 源代码作为练习 我遇到了以前从未遇到过的情况 即在同一个语句中对同一个变量进行了两次赋值 e g variable 表达 表达 这里究竟发生了什么 这是一个相当普遍的事情吗 双重作业的目的
  • 有效连接多个 sas 数据集

    我有超过 200k 个具有相同变量 n macro catDat name nbr call in new dataset data new set libin name run reorder names proc sql noprint
  • ie11 的 CSS 自定义属性 polyfill

    有没有办法用 JavaScript 来 pollyfill ie11 的自定义 CSS 属性 我在考虑加载 检查浏览器是否支持自定义属性 如果不支持 则对属性进行某种查找和替换 这可以通过 JavaScript 或某些库实现吗 Thanks
  • 客户端 javascript 相当于 Lucene

    我想知道是否有一个相当于 Lucene API 的 Javascript 旨在用于客户端来索引相对较小的数据集 一个示例用例是静态站点 例如生成的 能够搜索内容而无需服务器端处理 我发现了这个 http lunrjs com http lu
  • Asp.net 验证错误消息更改标签文本

    我正在使用 asp net 验证控件来验证用户输入 我想要的是使用验证控件生成的错误消息更改标签文本
  • 角度 (1.5.8) 动态组件

    我正在尝试使用 Angular 1 5 8 构建一种动态仪表板 直到最后一个障碍 我已经取得了不错的进步 这实际上是在渲染动态组件 我尝试了 2 个选项 要么添加一个ui view并以编程方式传递小部件的名称 or 这就是我猜的路线more
  • 将参数从父函数传递给嵌套函数Python

    这是我的代码 def f x def g n if n lt 10 x x 1 g n 1 g 0 当我评估 f 0 时 会出现错误 赋值前引用了 x 但是 当我使用 print x 而不是 x x 1 时 它会起作用 看来在 g 的范围内
  • C# 定时器或 Thread.Sleep

    我正在运行 Windows 服务并使用循环和 Thread Sleep 来重复任务 使用计时器方法会更好吗 如果是的话 代码示例会很棒 我目前正在使用此代码来重复 int curMinute int lastMinute DateTime
  • 枚举的通用类,值的数量

    我如何知道我的枚举在此示例中有多少个值 public class Analyser
  • 如何使用服务的输入/输出动态创建组件实例并将其单独注入到 DOM 中?

    在 Angular 2 中创建动态组件时 我found https stackoverflow com questions 36325212 angular 2 dynamic tabs with user click chosen com