首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >具有用户单击所选组件的动态选项卡

具有用户单击所选组件的动态选项卡
EN

Stack Overflow用户
提问于 2016-03-31 13:53:44
回答 3查看 162.5K关注 0票数 232

我正在尝试设置一个选项卡系统,允许组件注册自身(带有标题)。第一个标签就像一个收件箱,有大量的动作/链接项目供用户选择,每一次点击都应该能够在点击时实例化一个新的组件。操作/链接来自JSON。

然后,实例化的组件会将自身注册为新选项卡。

我不确定这是不是最好的方法?到目前为止,我看到的唯一指南是静态标签,这是没有帮助的。

到目前为止,我只得到了在main中引导的tabs服务,可以在整个应用程序中持久化。它看起来像这样:

代码语言:javascript
复制
export interface ITab { title: string; }

@Injectable()
export class TabsService {
    private tabs = new Set<ITab>();

    addTab(title: string): ITab {
        let tab: ITab = { title };
        this.tabs.add(tab);
        return tab;
    }

    removeTab(tab: ITab) {
        this.tabs.delete(tab);
    }
}

问题:

  1. 如何在创建新(不同)选项卡的收件箱中创建动态列表?我猜测会使用DynamicComponentBuilder
  2. 如何从收件箱(单击)创建组件,并将其注册为选项卡并显示?我猜是ng-content,但我找不到多少关于如何使用

的信息

EDIT:是一个澄清的尝试。

把收件箱想象成一个邮件收件箱。项目以JSON的形式获取,并显示多个项目。一旦单击其中一个项目,就会创建一个新的选项卡,其中包含该项目的操作“type”。然后该类型就是一个组件。

编辑2: Image

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-03-31 14:10:18

更新

更新

4.0.0-beta.3中增加了ngComponentOutlet

更新

有一个正在进行的执行类似https://github.com/angular/angular/pull/11235NgComponentOutlet工作

RC.7

代码语言:javascript
复制
// Helper component to add dynamic components
@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target: ViewContainerRef;
  @Input() type: Type<Component>;
  cmpRef: ComponentRef<Component>;
  private isViewInitialized:boolean = false;

  constructor(private componentFactoryResolver: ComponentFactoryResolver, private compiler: Compiler) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      // when the `type` input changes we destroy a previously 
      // created component before creating the new one
      this.cmpRef.destroy();
    }

    let factory = this.componentFactoryResolver.resolveComponentFactory(this.type);
    this.cmpRef = this.target.createComponent(factory)
    // to access the created instance use
    // this.compRef.instance.someProperty = 'someValue';
    // this.compRef.instance.someOutput.subscribe(val => doSomething());
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

使用示例

代码语言:javascript
复制
// Use dcl-wrapper component
@Component({
  selector: 'my-tabs',
  template: `
  <h2>Tabs</h2>
  <div *ngFor="let tab of tabs">
    <dcl-wrapper [type]="tab"></dcl-wrapper>
  </div>
`
})
export class Tabs {
  @Input() tabs;
}
代码语言:javascript
复制
@Component({
  selector: 'my-app',
  template: `
  <h2>Hello {{name}}</h2>
  <my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
  // The list of components to create tabs from
  types = [C3, C1, C2, C3, C3, C1, C1];
}
代码语言:javascript
复制
@NgModule({
  imports: [ BrowserModule ],
  declarations: [ App, DclWrapper, Tabs, C1, C2, C3],
  entryComponents: [C1, C2, C3],
  bootstrap: [ App ]
})
export class AppModule {}

另请参阅angular.io DYNAMIC COMPONENT LOADER

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx旧版本

这在Angular2 RCla中再次发生了变化

我将更新下面的示例,但这是假期前的最后一天。

这个Plunker example演示了如何在RC.5中动态创建组件

.createComponent()更新-使用

由于DynamicComponentLoader已被弃用,因此需要再次更新该方法。

代码语言:javascript
复制
@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private resolver: ComponentResolver) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
   this.resolver.resolveComponent(this.type).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory)
      // to access the created instance use
      // this.compRef.instance.someProperty = 'someValue';
      // this.compRef.instance.someOutput.subscribe(val => doSomething());
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

更新-使用loadNextToLocation

代码语言:javascript
复制
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private dcl:DynamicComponentLoader) {}

  updateComponent() {
    // should be executed every time `type` changes but not before `ngAfterViewInit()` was called 
    // to have `target` initialized
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
    this.dcl.loadNextToLocation(this.type, this.target).then((cmpRef) => {
      this.cmpRef = cmpRef;
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

原始

从你的问题中我不能完全确定你的需求是什么,但我认为这应该能满足你的需求。

Tabs组件获得一个传递的类型数组,并为数组中的每一项创建“制表符”。

代码语言:javascript
复制
@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  constructor(private elRef:ElementRef, private dcl:DynamicComponentLoader) {}
  @Input() type;

  ngOnChanges() {
    if(this.cmpRef) {
      this.cmpRef.dispose();
    }
    this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
      this.cmpRef = cmpRef;
    });
  }
}

@Component({
  selector: 'c1',
  template: `<h2>c1</h2>`

})
export class C1 {
}

@Component({
  selector: 'c2',
  template: `<h2>c2</h2>`

})
export class C2 {
}

@Component({
  selector: 'c3',
  template: `<h2>c3</h2>`

})
export class C3 {
}

@Component({
  selector: 'my-tabs',
  directives: [DclWrapper],
  template: `
  <h2>Tabs</h2>
  <div *ngFor="let tab of tabs">
    <dcl-wrapper [type]="tab"></dcl-wrapper>
  </div>
`
})
export class Tabs {
  @Input() tabs;
}


@Component({
  selector: 'my-app',
  directives: [Tabs]
  template: `
  <h2>Hello {{name}}</h2>
  <my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
  types = [C3, C1, C2, C3, C3, C1, C1];
}

(不是基于您的柱塞)

还有一种传递数据的方法,可以传递给动态创建的组件,比如(需要像type一样传递someData)

代码语言:javascript
复制
    this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
  cmpRef.instance.someProperty = someData;
  this.cmpRef = cmpRef;
});

还有一些支持在共享服务中使用依赖注入。

有关更多详细信息,请参阅https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html

票数 275
EN

Stack Overflow用户

发布于 2016-06-21 04:52:13

我还不够酷,不能发表评论。我从公认的答案中修复了柱塞,以便为rc2工作。没什么花哨的,只是CDN的链接断了而已。

代码语言:javascript
复制
'@angular/core': {
  main: 'bundles/core.umd.js',
  defaultExtension: 'js'
},
'@angular/compiler': {
  main: 'bundles/compiler.umd.js',
  defaultExtension: 'js'
},
'@angular/common': {
  main: 'bundles/common.umd.js',
  defaultExtension: 'js'
},
'@angular/platform-browser-dynamic': {
  main: 'bundles/platform-browser-dynamic.umd.js',
  defaultExtension: 'js'
},
'@angular/platform-browser': {
  main: 'bundles/platform-browser.umd.js',
  defaultExtension: 'js'
},

https://plnkr.co/edit/kVJvI1vkzrLZJeRFsZuv?p=preview

票数 20
EN

Stack Overflow用户

发布于 2016-07-29 21:09:06

有可供使用的组件(与rc5兼容) ng2-steps,它使用Compiler将组件注入到步骤容器和服务中,以便将所有内容连接在一起(数据同步)

代码语言:javascript
复制
    import { Directive , Input, OnInit, Compiler , ViewContainerRef } from '@angular/core';

import { StepsService } from './ng2-steps';

@Directive({
  selector:'[ng2-step]'
})
export class StepDirective implements OnInit{

  @Input('content') content:any;
  @Input('index') index:string;
  public instance;

  constructor(
    private compiler:Compiler,
    private viewContainerRef:ViewContainerRef,
    private sds:StepsService
  ){}

  ngOnInit(){
    //Magic!
    this.compiler.compileComponentAsync(this.content).then((cmpFactory)=>{
      const injector = this.viewContainerRef.injector;
      this.viewContainerRef.createComponent(cmpFactory, 0,  injector);
    });
  }

}
票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36325212

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档