Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有办法在Angular中动态插入现有组件?_Angular - Fatal编程技术网

有没有办法在Angular中动态插入现有组件?

有没有办法在Angular中动态插入现有组件?,angular,Angular,我有一种情况,Angular认为它需要重新创建组件,而不仅仅是使用旧组件,这会导致组件在拖动到界面中的另一个位置后“刷新”。我有一个树,从中生成组件。以下是my tree的简化版本: { "left": { "type": "FirstComponent" }, "right": { "left": { "type": "SecondComponent" }, "right": { "type": "ThirdComponent

我有一种情况,Angular认为它需要重新创建组件,而不仅仅是使用旧组件,这会导致组件在拖动到界面中的另一个位置后“刷新”。我有一个树,从中生成组件。以下是my tree的简化版本:

{
  "left": {
    "type": "FirstComponent"
  },
  "right": {
    "left": {
      "type": "SecondComponent"
    },
    "right": {
      "type": "ThirdComponent"
    }
  }
}
将零部件拖动到另一个位置后:

{
  "left": {
    "left": {
      "type": "FirstComponent"
    },
    "right": {
      "type": "ThirdComponent"
    }
  },
  "right": {
    "type": "SecondComponent"
  }
}
我在DockComponent中动态插入组件,如下所示:

private panelRef: ComponentRef<any>;

ngOnChanges() {
  const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.panel.type);
  this.dynamicInsert.clear();
  this.panelRef = this.dynamicInsert.createComponent(componentFactory);
}
不幸的是,这不起作用,因为我的组件是使用如下树递归创建的:

<div class="dock-orientation {{getOrientation()}}">
  <div *ngIf="isPanel(dockTree.getLeft()); then leftDock else leftContainer"></div>
  <div *ngIf="isPanel(dockTree.getRight()); then rightDock else rightContainer"></div>
</div>

<ng-template #leftDock>
  <ct-dock class="dock-node dock" [panel]="leftAsPanel()"></ct-dock>
</ng-template>

<ng-template #rightDock>
  <ct-dock class="dock-node dock" [panel]="rightAsPanel()"></ct-dock>
</ng-template>

<ng-template #leftContainer>
  <ct-dock-container class="dock-node dock-container" [dockTree]="leftAsContainer()"></ct-dock-container>
</ng-template>

<ng-template #rightContainer>
  <ct-dock-container class="dock-node dock-container" [dockTree]="rightAsContainer()"></ct-dock-container>
</ng-template>
[edit3]

终于成功了。我正在使用AfterViewChecked钩子查看是否已初始化面板。如果没有,我们就重新使用旧的。AfterViewChecked给出了更改检测的问题,所以您需要调用detectChanges()!接受伊利亚的回答,因为它帮助我找到了答案

ngOnInit(): void {
    // Detach our panel on changes in the dockTree
    this.dockTreeSub = this.dockerService.getTreeChange().subscribe((value) => {
      if (value !== '') {
        if (this.dynamicInsert.length > 0) {
          this.detachPanel();
        }
      }
    });

    if (!this.panel.ref && this.dynamicInsert.length <= 0) {
      this.createNewComponent();
    }
  }

  /**
   * Check if the panel needs to be re-inserted after moving panels
   */
  ngAfterViewChecked(): void {
    if (this.panel.ref && this.dynamicInsert.length <= 0) {
      this.insertExistingComponent();
    }
    this.changeDetector.detectChanges();
  }
ngOnInit():void{
//分离dockTree中的更改面板
this.dockTreeSub=this.dockerService.getTreeChange().subscribe((值)=>{
如果(值!=''){
如果(this.dynamicSert.length>0){
这个.detachPanel();
}
}
});
如果(!this.panel.ref&&this.dynamicInsert.length
@组件({
模板:“动态”,
})
导出类DynamicComponent{}
@组成部分({
选择器:“你好”,
模板:`
交换`,
})
导出类HelloComponent{
@ViewChild('firstContainer',{read:ViewContainerRef})firstContainer:ViewContainerRef;
@ViewChild('secondContainer',{read:ViewContainerRef})secondContainer:ViewContainerRef;
工厂;
构造函数(解析程序:ComponentFactoryResolver){
this.factory=resolver.resolveComponentFactory(DynamicComponent);
}
恩戈尼尼特(){
this.firstContainer.createComponent(this.factory);
this.secondContainer.createComponent(this.factory);
}
互换{
const first=this.firstContainer.get(0);
const second=this.secondContainer.get(0);
此.firstContainer.detach(0);
此.secondContainer.detach(0);
this.firstContainer.insert(第二个);
此.secondContainer.insert(第一个);
}
}

我尝试过这样做。问题是我正在使用树递归创建插入视图的组件。当ngOnInit为我的DockComponent启动时,旧的ViewRef已全部销毁。我无法像这样进行真正的交换,因为交换并不总是发生在同一个组件中。答案应该包括more不仅仅是一个代码片段。解释为什么你的建议有效,为什么OP的代码无效,以及两者的不同之处。这需要更多的挖掘,但这是答案的核心。解决方案很复杂。如果在销毁组件之前将
ViewRef
与当前
ViewContainerRef
分离会怎么样(在Ngondestory中)?这样,
ViewRef
就不应该被销毁。并且在父组件的
ngondestory
中销毁它们以防止内存泄漏。为什么面板没有初始化?我订阅了一个可观察的,如果我更改树,我会调用它。因此每个面板都会分离它们的ViewRef。每个实际有更改的面板都会经过init和所有内容,但并非所有面板都由更改检测触发。
<div class="dock-orientation {{getOrientation()}}">
  <div *ngIf="isPanel(dockTree.getLeft()); then leftDock else leftContainer"></div>
  <div *ngIf="isPanel(dockTree.getRight()); then rightDock else rightContainer"></div>
</div>

<ng-template #leftDock>
  <ct-dock class="dock-node dock" [panel]="leftAsPanel()"></ct-dock>
</ng-template>

<ng-template #rightDock>
  <ct-dock class="dock-node dock" [panel]="rightAsPanel()"></ct-dock>
</ng-template>

<ng-template #leftContainer>
  <ct-dock-container class="dock-node dock-container" [dockTree]="leftAsContainer()"></ct-dock-container>
</ng-template>

<ng-template #rightContainer>
  <ct-dock-container class="dock-node dock-container" [dockTree]="rightAsContainer()"></ct-dock-container>
</ng-template>
// getTreeChange is an Observable that gets triggered after each change in the dockTree, which detaches all the panels in the application.
ngOnInit(): void {
  // Detach our panel on changes in the dockTree
  this.dockTreeSub = this.dockerService.getTreeChange().subscribe((value) => {
    if (value !== '') {
      if (this.dynamicInsert.length > 0) {
        this.detachPanel();
      }
    }
  });
}

ngAfterViewInit(): void {
  if (this.panel.ref) {
    this.insertExistingComponent();
  } else {
    this.createNewComponent();
  }
}

/**
 * Creates a new component and inserts it into the Dock
 */
private createNewComponent() {
  console.log('No panel ref found, creating new component');
  const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.panel.type);
  this.panelRef = this.dynamicInsert.createComponent(componentFactory);
  this.initializePanel(this.panelRef.instance);
  this.panelRef.instance['panel'] = this.panel;
}

/**
 * Takes the old ViewRef from memory and inserts that into the Dock
 */
private insertExistingComponent() {
  if (this.panel.ref.destroyed) {
    throw new Error('Found destroyed panel');
  }
  console.log('Found intact panel, inserting');
  this.dynamicInsert.clear();
  this.dynamicInsert.insert(this.panel.ref);
}

/**
 * Detach the panel from this Dock and save it in the DockTree
 */
private detachPanel() {
  console.log('Detaching!');
  this.panel.ref = this.dynamicInsert.get(0);
  this.dynamicInsert.detach(0);
}
ngOnInit(): void {
    // Detach our panel on changes in the dockTree
    this.dockTreeSub = this.dockerService.getTreeChange().subscribe((value) => {
      if (value !== '') {
        if (this.dynamicInsert.length > 0) {
          this.detachPanel();
        }
      }
    });

    if (!this.panel.ref && this.dynamicInsert.length <= 0) {
      this.createNewComponent();
    }
  }

  /**
   * Check if the panel needs to be re-inserted after moving panels
   */
  ngAfterViewChecked(): void {
    if (this.panel.ref && this.dynamicInsert.length <= 0) {
      this.insertExistingComponent();
    }
    this.changeDetector.detectChanges();
  }
@Component({
  template: 'dynamic <input>',
})
export class DynamicComponent {}


@Component({
  selector: 'hello',
  template: `
  <ng-container #firstContainer></ng-container>
  <ng-container #secondContainer></ng-container>
  <button (click)="swap()">swap</button>`,
})
export class HelloComponent  {
  @ViewChild('firstContainer', {read: ViewContainerRef}) firstContainer: ViewContainerRef;
  @ViewChild('secondContainer', {read: ViewContainerRef}) secondContainer: ViewContainerRef;
  factory;
  constructor(resolver: ComponentFactoryResolver) {
    this.factory = resolver.resolveComponentFactory(DynamicComponent);
  }
  ngOnInit() {
    this.firstContainer.createComponent(this.factory);
    this.secondContainer.createComponent(this.factory);
  }
  swap() {
    const first = this.firstContainer.get(0);
    const second = this.secondContainer.get(0);
    this.firstContainer.detach(0);
    this.secondContainer.detach(0);
    this.firstContainer.insert(second);
    this.secondContainer.insert(first);
  }
}