4

我正在尝试在选项卡中加载组件。在单击特定选项卡时,我需要加载特定组件。但它在导航到该组件时会加载所有组件。

.html

<p-tabView orientation="left" (onChange)="onTabChange($event)">
       <p-tabPanel *ngFor="let item of items" style="border: solid 1px; padding: 20px;margin: 20px;" [selected]="activeTabIndex==i">
              <strong> When you click here, 
              I should load the <span style="color:red"> {{item.name}} </span>
              component below</strong> <br />

              <ng-container *ngComponentOutlet="childmap[item.name] "></ng-container>

          <br />
        </p-tabPanel>
</p-tabView>

.ts

@Component({
  selector: 'my-app',
  templateUrl:'dashboard.html' 
  `
})
export class App {
 activeTabIndex: number = 0;

childmap = {
        'slider': sliderComponent,
        'user': usersComponent,
        'alert danger': AlertDangerComponent
         }


items:Array<any> = [
    {
      name: 'slider' 
    },
    {
      name: 'user'
    },
    {
      name: 'alert danger'
    }

      ]
 onTabChange(event: any) {
        this.activeTabIndex = event.index;
    }
  }
4

2 回答 2

4

这种事情有很多解决方案。请我使用ngComponentOutlet.

这是选项卡容器:

import {Component, Input} from '@angular/core'
import {TabContentAlternativeComponent} from './tab-content-alternative.component'
import {BasicContent} from './basic-content'

@Component({
  selector: 'tab',
  template: ''
})
export class TabComponent {
  @Input() title: string;
  @Input() contentRef: BasicContent;
  active = false;
}

这是一个非常简单的组件,它知道自己的选项卡名称、活动状态和当有人选择选项卡时应该加载的主体组件引用。

然后我们创建几个将动态加载的 body 组件:

export class BasicContent {

}

组件 1

  import {Component, Input, OnInit} from '@angular/core'
import {BasicContent} from './basic-content'

@Component({
  selector: 'tab-content',
  template: `
      <p>Hey</p>
  `,
})
export class TabContentComponent extends BasicContent {
}

组件 2

   import {Component, Input} from '@angular/core'
import {BasicContent} from './basic-content'

@Component({
  selector: 'tab-content-alternative',
  template: `
      <p>Hey, this is an alternative content</p>
  `,
})
export class TabContentAlternativeComponent extends BasicContent {
}

这是带有标签渲染的标签容器组件和用于动态主体组件的空占位符:

    import {AfterContentInit, Component, ContentChildren, QueryList} from '@angular/core'
import {TabComponent} from './tab.component'
import {BasicContent} from 'basic-content'

import 'rxjs/Rx';
import {Observable, BehaviorSubject} from 'rxjs/Rx';

@Component({
  selector: 'tab-container',
  template: `
    <div class="tab-header">
      <div class="tab" *ngFor="let tab of tabs" (click)="selectTab(tab)" [class.active]="tab.active">{{tab.title}}</div>
    </div>

    <div class="tab-content">
      <ng-container *ngComponentOutlet="content | async"></ng-container>
    </div>
  `,
})
export class TabContainerComponent implements AfterContentInit {
  @ContentChildren(TabComponent) tabs: QueryList<TabComponent>;

  private contentSbj = new BehaviorSubject<BasicContent>(null);
  content = this.contentSbj.asObservable();

  ngAfterContentInit() {
    const activeTabs = this.tabs.filter((tab) => tab.active);
    if (activeTabs.length === 0) {
      this.selectTab(this.tabs.first);
    }
  }

  selectTab(tab: TabComponent) {
    this.tabs.toArray().forEach(tab => tab.active = false);
    tab.active = true;
    this.contentSbj.next(tab.contentRef);
  }
}

标题映射

import {TabContentComponent} from './tab-content.component';
import {TabContentAlternativeComponent} from './tab-content-alternative.component';

interface TitleMapping {
  title: string;
  contentComponent: BasicContent;
}

export const allTabs: TitleMapping[] = [
  {title: "Tab 1", contentComponent: TabContentComponent},
  {title: "Tab 2", contentComponent: TabContentAlternativeComponent},
  {title: "Tab 3", contentComponent: TabContentComponent}
]

这就是它在某些父组件中的使用方式:

import {TabContentComponent} from './tab/tab-content.component'
import {TabContentAlternativeComponent} from './tab/tab-content-alternative.component'

@Component({
  selector: 'my-app',
  template: `
    <tab-container>
      <tab title="Tab 1" [contentRef]="normalContent"></tab>
      <tab title="Tab 2" [contentRef]="alternativeContent"></tab>
    </tab-container>
  `,
})
export class App {
  normalContent = TabContentComponent;
  alternativeContent = TabContentAlternativeComponent;
}

这是工作Plunkr

我已经在我的项目中使用了它,并且可以根据您的要求正常工作。

于 2017-12-09T10:59:18.097 回答
3

您所做的基本上是尝试编写自己的路由器。PrimeNg TabView 被构建为在初始化时首先加载菜单和所有选项卡内容,然后在其顶部放置一个人造的选项卡层。但是,在菜单下,有 TabMenu 这实际上是您想要的。关键区别在于,菜单允许您的列表是可以包含 routerLink 作为参数的MenuItems 。

这里有一篇优秀的文章解释了我更喜欢官方文档的细节。你应该先理解这一点,然后看看 PrimeNg 是如何实现一个方便的方法来为你构建这些链接的,如果你提供了 routerLink。(有关 MenuItem 模型的更好文档,请参阅 MenuItems 链接。从您的代码中,我无法判断您是否处于顶级组件中,但我认为您正在寻找的是沿着这些路线。此解决方案使用子路由这稍微复杂一些,但更有用的例子。这假设您将 AppComponent 设置为仅<router-outlet></router-outlet>在模板中的顶级组件。这将加载您的仪表板组件作为一个空的根重定向到仪表板。

app.module.ts

const myDefinedRoutes: Routes = [
  {path: '', redirectTo: 'dashboard', pathMatch: 'full'},
  {path: 'dashboard', component: DashboardComponent, children: [
      {path: 'slider', component: SliderComponent},
      {path: 'user', component: UserComponent},
      {path: 'alert', component: AlertDangerComponent},
    ]
  }
]

@NgModule({
  // Add this line to imports
    RouterModule.forRoot(myDefinedRoutes)
})
export class AppModule {}

仪表板.component.ts

@Component({
  selector: 'my-app',
  template:`
   <p-tabMenu [model]="items"></p-tabMenu>
   <router-outlet></router-outlet>
  `
})
export class App implements OnInit {
  ngOnInit() {
    this.items = [
      {label: "Slider", routerLink: ['/dashboard', 'slider']},
      {label: "User", routerLink: ['/dashboard', 'user']},
      {label: "Danger", routerLink: ['/dashboard', 'alert']},
    ];
    this.activeItem = this.items[1]
  }
}

确保在仪表板组件中也包含路由器插座,因为其他组件作为子组件存在,这意味着您将需要另一个插座,因为第一个插座仍然容纳仪表板组件,并且在仪表板组件内部,您正在显示其中一个其他三个组件。

于 2017-12-05T04:30:41.377 回答