Angular 5: 切换动态组件位置

13

我想交换视图中动态放置组件的位置。

即,我已经创建了具有id = 1和2的动态组件,如图所示。

enter image description here

现在,我需要交换两个组件的位置,但是怎么做呢?

唯一知道(理论上)的事情是,可以通过ViewContainerRef class中的move方法通过对象更改位置,例如viewContainerRef.move(componentRef.hostView, index)

我尝试过了,但位置并没有交换。

@ViewChild(ContainerRefDirective) location: ContainerRefDirective;

let componentFactory = this.factoryResolver.resolveComponentFactory(EntryComponent);
let componentRef = this.location.viewContainerRef.createComponent(componentFactory);

let entryComponent: EntryComponent = componentRef.instance;
// lets say counter is variable that increments its value on new component creation.
entryComponent.Id = ++counter; 

// move method is being called right after a new component is created and placed. 
//this piece of code is in the same method (that is creating the dynamic components)
this.location.viewContainerRef.move(componentRef.hostView, 1);

我已经阅读了关于angular.io中的ViewContainerRef文档并且阅读了几乎相同的问题,但是仍然无法理解或解决此问题。

3个回答

10

为什么不将你的两个动态组件绑定到一个数组中呢? 例如,如果你有一个“objectA”和“objectB”:

this.renderArray.push(objectA);
..
this.renderArray.push(objectB);

而你的 HTML 看起来像这样:

<ng-container *ngFor="let renderObject of renderArray">
   <<you can reference objectA and objectB by using "renderObject.value" etc.>>
</ng-container>

当您需要交换它们的位置时,只需操作数组,angular会处理其余部分:

this.renderArray = this.renderArray.reverse();

它将以新的顺序重新渲染ngFor容器。 请查看此处的工作示例


使用 ViewContainerRef.move(ref, index) 方法无法交换动态组件的位置。如果可以,那么如何实现? - WasiF
我根据您的描述添加了组件,但现在出现了意外的错误“您是否将其添加到@NgModule.entryComponents? 在noComponentFactoryError中”。尽管我已经将该组件添加到了“entryComponents”。 - WasiF
2
为什么需要在控制类中处理组件引用?如果可能的话,您应该让Angular渲染引擎来处理它。只需专注于数据,并相应地进行绑定。因此,不要绑定组件,而是绑定数据,即在组件上的数据。(如果您正在使用动态组件绑定,则恐怕我的方法无法使用) - ForestG
感谢您宝贵的建议。我改变了数值而不是改变组件位置,这给了我我的结果。 - WasiF
是的,它没有帮助我或者我无法理解它。 - WasiF
显示剩余9条评论

6

解决了这个问题。

我做了什么?

我改变了值,而不是交换组件的位置

也就是说,我替换了值1 <=> 2,看起来组件已经交换位置了。

如何操作?

// array to hold the newly created component instances
entryComponents: EntryComponent[] = new Array<EntryComponent>();

然后将新创建的组件推入该数组。
let factoryResolver = this.factoryResolver.resolveComponentFactory(EntryComponent);    
let componentRef = this.location.viewContainerRef.createComponent(factoryResolver);

this.entryComponents.push(componentRef.instance); // getting components' instances

现在交换这些值,以便组件看起来被交换了。
感谢@ForestG提出的建议。

你好!我想知道为什么您不能简单地编辑另一个答案,因为它是这个答案的基础?进行一些清理并可能给Forest他的好答案点赞会更明智。 - Zlatko
我很感激他的努力,但他的答案完全不同,对我的情况没有用。在他的评论中,他建议更改对象值而不是对象位置。 - WasiF

3
我尚未尝试过这个方法,但是根据文档来看,似乎move不是正确的方法。 看起来move是用于将现有组件“添加”到视图中的。从detach的文档中可以得知:

与insert一起使用以将View移动到当前容器内。

基于这一行,我建议...
let ref = this.location.viewContainerRef;
ref.detach(ref.indexOf(componentRef.hostView));
ref.insert(componentRef.hostView, 0);

编辑 我使用Angular的实时示例为动态组件加载器创建了一个工作示例

以下是与问题相关的代码:

// ShaneCoder - don't clear so we get multiple ads to demonstrate move.
// viewContainerRef.clear();

// ShaneCoder - only create 4 ads
if (viewContainerRef.length<4) {

    let componentRef = viewContainerRef.createComponent(componentFactory);
    (<AdComponent>componentRef.instance).data = adItem.data;

    // ShaneCoder ad is inserted at the bottom (no index parameter).  Move it up if there are multiple ads.
    if (viewContainerRef.length>=1) {
        // we're not the first ad
        // move new ad to top using detach and insert (the next two lines answer the original question) 
        viewContainerRef.detach(viewContainerRef.indexOf(componentRef.hostView));
        viewContainerRef.insert(componentRef.hostView, 0);
        // comment out the previous two lines to see that ads are inserted at the bottom.
    }
}

编辑2

在发布最后一次编辑后,我意识到我没有尝试过 move 。用 move 替换了 detach insert ,它就起作用了。 这里是示例。 相关代码:

viewContainerRef.move(componentRef.hostView, 0);
// comment out the previous two lines to see that ads are inserted at the bottom.

现在我想知道你之前遇到的问题是否与move的零索引有关。如果要使组件成为容器视图中的第一个,请传递零作为索引;如果要使其成为第二个,则传递一,以此类推。因此,你的代码将会像这样改变:

this.location.viewContainerRef.move(componentRef.hostView, 0);

建议使用实际实现的方法来交换组件,例如移动、分离或插入等现有方法。我将为您提供此赏金。赏金还剩一个小时即将到期。 - WasiF
感谢您提供两种不同的方法来交换容器中的组件,以及宝贵的时间和精力。 - WasiF

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接