使用已知/声明的组件插入动态Angular 4.x内容 [英] Insert dynamic Angular 4.x content with known/declared components

查看:105
本文介绍了使用已知/声明的组件插入动态Angular 4.x内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个(我认为这是相当普遍的)问题,我找不到解决当前Angular 4.x架构的好方法.也许我还没有找到一种方法,但是我已经进行了广泛的搜索.

I have a (what I think would be a fairly common) problem that I cannot find a good way to solve with the current Angular 4.x architecture. Maybe there is a method that I haven't found yet, but I have searched pretty extensively.

我想将一些动态的,用户生成的HTML内容插入到Angular应用中.此HTML内容还包括一些应渲染的已知(包含在模块声明中)Angular组件.以下是一些puesdo-app HTML可能会帮助我解释的问题:

I would like to insert some dynamic, user generated HTML content into an Angular app. This HTML content my also include some known(included in the module declaration) Angular components that should be rendered. Below is some puesdo-app HTML might help me explain:

<app-component>

    <!-- standard angular header and router-outlet -->
    <app-header>
        <app-nav>
            <ul>
                <li routerLink="/page-one">First Page</li>
                <li routerLink="/page-two">Second Page</li>
                <li routerLink="/page-three">Third Page</li>
            </ul>
        </app-nav>
    </app-header>
    <router-outlet></router-outlet>

    <!--
        the dynamic content would be inserted into the <main> element as HTML with angular <app-... tags
        the content in the HTML content inserted main tag could contain anything
        the angular components within the content should be initalized as normal
    -->
    <main>
        <h1>Title</h1>
        <app-component>
            <p>this component and its content should be initalized when HTML is inserted into main</p>
        </app-component>
        <app-component>
            <app-sub-component>
                angular components here might also contain other angular components
            </app-sub-component>
        </app-component>
        <p>more regular HTML content</p>
    </main>

    <!-- more traditional Angular components could come after -->
    <app-footer></app-footer>

</app-component>

我尝试了两种方法来实现此目的,但这两种方法均无法真正起作用.

I have tried two methods of achieving this, neither of which truly work.

TLDR; 不适用于AOT. AOT是全有还是全无.

TLDR; It doesn't work with AOT. The AOT is all or nothing.

我使用了动态组件模式,例如

I've used a dynamic component pattern like this one. This is very simple to implement. Using the JIT Compiler, make a new Component and Module out of the HTML content, and insert an instance of the new component. This works as long as the project is not compiled AOT. Since Angular 4.x the JitCompilerFactory cannot be included in an AOT compiled build. It seems like it might make sense to allow the JIT Complier into AOT compiled builds so known components can get the performance boost, and use the JIT Compiler just for dynamic components. It would be the best of both worlds. BUT, I don't know the inner workings of Angular and I assume there is a good reason not to allow the JIT Compiler's inclusion.

TLDR; 无法获得加载组件的入口点.

TLDR; Can't get an entry point to load the components.

在AOT构建中遇到有关JIT编译器的问题后,我以为我可以使用ComponentFactoryResolver.由于我仅使用模块中已声明的组件,因此可以在HTML内容中应放置的位置处创建一个组件.这个想法有点疯狂,但我认为它可能有用.我的方法如下:

After my issues with the JIT Compiler in an AOT build, I thought I could maybe use the ComponentFactoryResolver. Since I'm only using components already declared in the module, I could just create a component in the place of where it should be in the HTML content. This idea is a little crazy, but I thought it might work. My approach would look like this:

  1. 插入动态HTML内容
    • 以HTML格式获取动态内容
    • 不要使用DomSanatizer.bypassSecurityTrustHtml()
    • 删除Angular组件
    • 并将其插入DOM
  1. Insert the dynamic HTML content
    • get dynamic content as HTML
    • don't remove Angular components using the DomSanatizer.bypassSecurityTrustHtml(),
    • and insert it into the DOM
  • 使用{<app-selector-string> : ComponentClass} json表
  • 将所有组件查找为DOM节点,并将其与相应的ComponentClass匹配
  • using an {<app-selector-string> : ComponentClass} json table
  • find all components as DOM Nodes and match them to their corresponding ComponentClass
  • 将其插入旧元素
  • 提供组件projectableNodes,它是旧html组件的内容
  • insert it in place of the old element
  • give the component projectableNodes that is the content of the old html component

这不起作用,因为不可能在第3步中动态创建ViewContainerRef.(在第3步之后也可能无法执行任何操作.IDK.我没有得到远)

This does not work because dynamically creating a ViewContainerRef in step 3 is not possible.(It may also not be possible to do anything after step 3. IDK. I didn't get that far)

有没有办法做到这一点?我在想吗?

Is there any way to do this? Am I over thinking it?

谢谢!

推荐答案

实际上,这很有可能...

This is very possible, actually...

Angular的ApplicationRef具有attachView()方法,该方法将跟踪新的组件引用.然后可以像常规组件一样在任何地方插入该组件引用.

Angular's ApplicationRef has an attachView() method that will keep track of a new component reference. That component reference can then be inserted anywhere just like a regular component.

这是一个伪代码示例:

// create a componentRef
const componentFactory = ComponentFactoryResolver.resolveComponentFactory(AngularComponent);
const componentRef = componentFactory.create(Injector);

// attach the componentRef to the angular ApplicationRef
ApplicationRef.attachView(componentRef.hostView);

// insert the root element of the new componentRef into any DOM node
const componentRoot: HTMLElement = (componentRef.hostView as EmbeddedViewRef<any>).rootNodes[0];
const node = document.getElementById('insertionPoint'); 
Renderer2.insertBefore(node.parentNode, componentRoot, node);

// don't forget to destroy the component when you're done with it
ApplicationRef.detachView(componentRef.hostView);
componentRef.destroy();

更好的解释此处

这篇关于使用已知/声明的组件插入动态Angular 4.x内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆