Angular 7-向动态创建的组件添加拖放行为

时间:2019-05-13 08:18:43

标签: javascript html angular drag-and-drop angular-components

这是我在SO上提出的上一个问题的延续: Add directives to component selector when it is declared - Angular 7

单击按钮后,我正在动态创建组件。这些组件以类似列表的方式一个接一个地显示。我想介绍一下拖放行为,以便用户在创建组件后可以重新排列它们。

在上一个问题中,我尝试使用Angular-Material,但意识到由于将“ cdkDrag”指令添加到组件的选择器标记以及cdkDropList的事实,可能无法将其用于组件和cdkDrag可能需要在同一模板中。

我在模板中有一个div,

<div cdkDropList style="margin: 20px" (cdkDropListDropped)="drop($event)">
    <div #container></div>
</div>

而且,我正在如下创建自定义组件:

@ViewChild('container', {read: ViewContainerRef})
  container: ViewContainerRef;

const childComponent = this.componentFactoryResolver.resolveComponentFactory(CustomComponent);
const component = this.container.createComponent(childComponent);

这很好。可以创建可拖动的动态创建的组件吗?

谢谢。

4 个答案:

答案 0 :(得分:1)

最后,由于MauriceNino的回复,它得以正常工作。我将把Maurice的答案标记为已接受,因为它们的解决方案对于单个组件来说效果很好。

在让莫里斯的解决方案适用于多个组件的同时,我遇到了一个名为ng-container的神奇概念!救命啊!我的解决方法如下:

components=[];

const childComponent = this.componentFactoryResolver.resolveComponentFactory(CustomComponent);
this.components.push(childComponent);


drop(event: CdkDragDrop<CmpComponent[]>) {
  moveItemInArray(this.components, event.previousIndex, event.currentIndex);
}

现在是模板:

<div cdkDropList class="example-list" style="margin: 20px" (cdkDropListDropped)="drop($event)">
    <ng-container *ngFor="let cmp of components">
        <ng-container *ngIf="cmp.componentType.name=='Component1'">
            <app-Component1 cdkDrag></app-Component1>
        </ng-container>
        <ng-container *ngIf="cmp.componentType.name=='Component2'">
            <app-Component2 cdkDrag></app-Component2>
        </ng-container>
        <ng-container *ngIf="cmp.componentType.name=='Component3'">
            <app-Component3 cdkDrag></app-Component3>
        </ng-container>

    </ng-container>
</div>

最后,经过一周的搜索,终于可以使用了! 谢谢!

答案 1 :(得分:0)

更新

虽然这对于一种单一类型的组件可以正常工作,但是如果您需要使用不同的动态类型的组件,请阅读下面的Chaitanya Bangera的注释!

原始评论

应该使用类似的东西(CmpComponent将是您要插入的组件):

  components: CmpComponent[];

const childComponent = this.componentFactoryResolver.resolveComponentFactory(CustomComponent);
this.components.push(childComponent);


drop(event: CdkDragDrop<CmpComponent[]>) {
  moveItemInArray(this.components, event.previousIndex, event.currentIndex);
}
<div cdkDropList style="margin: 20px" (cdkDropListDropped)="drop($event)">
    <div cdkDrag *ngFor="let cmp of components">
        <app-cmp></app-cmp>
    </div>
</div>

答案 2 :(得分:0)

我已经通过用createComponent方法动态生成组件并通过ViewComponentRef方法处理移动来解决了这个问题:

container.component.html

if ($row['rank'] == 1 || $row['rank'] == 2 || $row['rank'] == 3) {
echo 'SHOW RANK NAME'; (Administrator, Moderador and Helper)
}

container.component.ts

<div cdkDropList (cdkDropListDropped)="drop($event)">
    <ng-container #cmpContainer></ng-container>
</div>

dynamic.component.html

import {CdkDragDrop, moveItemInArray} from "@angular/cdk/drag-drop";

@ViewChild('cmpContainer', {static: true, read: ViewContainerRef}) cmpContainer: ViewContainerRef;
components: ComponentRef<Dynamic>[] = [];

addComponent() {
    const factory = this.cfr.resolveComponentFactory(Dynamic);
    const component: ComponentRef<Dynamic> = this.cmpContainer.createComponent(factory);
}

drop(event: CdkDragDrop<PollQuestionCardComponent[]>) {
    this.cmpContainer.move(this.components[event.previousIndex].hostView, event.currentIndex);
    moveItemInArray(this.components, prevIndex, currentIndex);
}
  • 在这种情况下,您可以直接通过components数组访问组件实例。

答案 3 :(得分:0)

您可以围绕每个 div 创建 ng-container 并为其设置 cdkDrag 属性。