指定索引处的动态组件未正确放置

Posted

技术标签:

【中文标题】指定索引处的动态组件未正确放置【英文标题】:Dynamic components at specified index not placed properly 【发布时间】:2018-12-30 18:35:40 【问题描述】:

我试图在 Angular 中显示一个简单的项目列表,旁边有一个可点击的 div;在用户选择时,组件应在点击的组件下方动态创建一个新组件。

为此,我使用ComponentFactoryResolver 没有相关问题;但是,使用ViewContainerRef 作为父级,我无法找到如何将创建的组件放置在指定索引处,即使我在createComponent() 方法中将其指定为参数。

app.component.html

<h3>Click on the arrow to create a component below the item clicked.</h3>

<div #myContainer>
  <div *ngFor="let thing of things; let index = index">
    <div class="inline click" (click)="thingSelected(thing, index)"> > </div>
    <div class="inline">thing.id</div>
    <div class="inline">thing.name</div>
    <div class="inline">thing.value</div>
  </div>
</div>

app.component.ts

export class AppComponent    
  @ViewChild('myContainer',  read: ViewContainerRef ) container: ViewContainerRef;

  things = [];
  constructor(private componentFactoryResolver: ComponentFactoryResolver)
    for(let i=0; i < 10; i++)
      this.things.push(id: i, name: "thing" + i, value: 5 * i);    
  

  thingSelected(thing: any, index: number)
    let component = this.container.createComponent(this.componentFactoryResolver.resolveComponentFactory(DetailComponent), index);
    component.instance.id = thing.id;    
  

我还创建了一个stackblitz 示例来演示该问题:我遗漏了什么或做错了什么?

澄清一下:

    我想在 PrimeNg 库的 TurboTable 中重现类似于 "RowExpand" functionality 的内容。 用户点击一行,在点击的位置创建了一个动态组件。 我不知道运行时组件的类型:这就是我想要创建动态组件的原因(因此,在 html 模板中指定它不是我需要的

【问题讨论】:

只要您的“索引集合”是连续的,您的示例就可以工作 - 所以为了在索引 5 处放置组件,您需要已经有 5 个组件。如果您添加从 0 到 9 的所有内容,您会注意到以后的任何添加都将按您的意愿工作。 \ 我需要将动态创建的组件插入到 NgFor 列表的“内部”,而不是在它的末尾。为了更清楚,我需要在 NgFor 的索引 N 处插入一个组件。 所以你真的想在 div 之间插入组件? 完全正确:我想重现 PrimeNg 的“RowExpand”之类的内容(请参阅我的问题中的链接) 【参考方案1】:

好的,这是@ViewChildren 的工作示例

https://stackblitz.com/edit/angular-gxmj4s?file=src%2Fapp%2Fapp.component.ts

  @ViewChildren('details',  read: ViewContainerRef ) containers: QueryList<ViewContainerRef>;

  thingSelected(thing: any, index: number) 
    const containersArray = this.containers.toArray();
    let component = containersArray[index].createComponent(this.componentFactoryResolver.resolveComponentFactory(DetailComponent));
    component.instance.id = thing.id;
  

<div #myContainer>
  <div *ngFor="let thing of things; let index = index">
    <div class="inline click" (click)="thingSelected(thing, index)"> > </div>
    <div class="inline">thing.id</div>
    <div class="inline">thing.name</div>
    <div class="inline">thing.value</div>
    <div #details></div>
  </div>
</div>

结果

【讨论】:

这解决了我的问题,但我想知道是否可以完全避免使用@vieChildren 和相关的 div:我想在容器中的某个索引处插入元素。在 jquery 中,我会这样解决这个问题: $('div:eq('+index'+)').after('myComponent'); 然后使用 jQuery 您当然知道,Angular 不鼓励使用 jquery,因为(几乎)它的所有功能都可以通过在 DOM 操作上使用 Angular API 来重现。实际上,ViewContainerRef 有一个叫做 insert() 的方法,可以用来在某个索引处插入一些组件。我不能只是找到一个正确的方法来使用它 (几乎)它的所有功能都可以通过在 DOM Manipulation 上使用 Angular API 来重现。 我刚刚这样做了,但您仍然不满意。您可以实现相同的目标,但没有人说它必须也不能以相同的方式完成。你需要看到那里的区别 虽然存在一个名为“insert()”的 api,但让我认为应该存在在 ViewContainerRef 中插入组件的可能性。无论如何感谢您的支持

以上是关于指定索引处的动态组件未正确放置的主要内容,如果未能解决你的问题,请参考以下文章

MUI createTheme 未正确将主题传递给 MUI 组件

Nativescript Angular Lifecycle 挂钩未将 css 类应用于动态组件

当我的路线放置在子组件中时,url正在更改但组件未呈现

静态和动态组件的选择

将对象添加到指定索引处的 ArrayList

ArrayListVector