我正在使用材料标签:https://material.angular.io/components/tabs/overview
我有一个带有选项卡视图的页面,我想用它来点击按钮为每个选项卡填充一个自定义组件.假设我有两个组件,其中包含选择器"customcomponent1"和"customcomponent2".我想这样做,当我点击一个按钮时,一个新的'对象'将被添加到列表中,如下所示:
{ 'COMPONENT_NAME': 'customcomponent1'}
一个新的选项卡"Tab2"将动态创建其中的组件,如果它是这样的:
<mat-tab-group>
<mat-tab label="Tab1">
<button (click)="createNewTabWithComponent('customcomponent1')"></button>
</mat-tab>
<mat-tab label="Tab2">
<customcomponent1></customcomponent1>
</mat-tab>
</mat-tab-group>
Run Code Online (Sandbox Code Playgroud)
如果我再次点击该按钮...我会得到一个新标签:
<mat-tab-group>
<mat-tab label="Tab1">
<button (click)="createNewTabWithComponent('customcomponent1')"></button>
</mat-tab>
<mat-tab label="Tab2">
<customcomponent1></customcomponent1>
</mat-tab>
<mat-tab label="Tab3">
<customcomponent2></customcomponent2>
</mat-tab>
</mat-tab-group>
Run Code Online (Sandbox Code Playgroud)
如何使用angular2/4实现此目的?我通常会使用类似$ compile的东西,但我不认为angular2/4有一个.我想避免的是为每个组件创建一堆标签(想象我有10个组件,真的不想为每个组件创建多个mat-tab占位符,并在每个组件上设置show/hide标志)和'硬编码'内部的一个组件.
如果解决方案显示如何使用选择器的名称"动态地"添加组件(用户在文本框中键入并按下按钮以'添加到选项卡),那么我认为这不是特定于选项卡的问题.列表',这也是一个考虑的答案.
我能想到的一个例子是,是否有文本框,有人可以键入任何字符串.如果字符串与组件的名称匹配,则该组件以编程方式"动态显示"在屏幕上,就好像它是原始模板的一部分一样.
我所知道的我所知道的伪代码是不存在的(我认为,如果它确实会很好):
<button (click)="addNameOfComponentToListOfCustomComponentStrings('text-from-a-textbox')">Add Component</button>
<div *ngFor="let string_name_of_component in listofcustomcomponentstrings">
<{{string_name_of_component}}><</{{string_name_of_component}}>
</div>
Run Code Online (Sandbox Code Playgroud)
将它们放入选项卡将是一个加号.如果这不可行,请发布.否则,请发布.
如果可能使用某些"嵌套角度路由"可以完成一个解决方法,它会根据ngFor中组件的名称提取组件,这可能也有效......对任何想法都是开放的.
对于您提出的问题(不希望有 10 个带有 *ngIf 的占位符 mat-tabs 来隐藏内容),您可以通过路由和延迟加载做得更好。
假设您的带有选项卡的页面位于/tabs,带有它的模块位于MyTabsModule。该模块的路由配置如下所示:
const routes = [{
path: 'tabs',
component: MyTabsComponent,
}];
Run Code Online (Sandbox Code Playgroud)
假设您有两个选项卡,left和right。您现在需要的是在惰性模块中添加子组件。就像这样简单的事情:
const routes = [{
path: 'tabs',
component: MyTabsComponent,
children: [
{
path: 'left',
loadChildren: 'app/lazy/left.module#LazyLeftModule'
},
{
path: 'right',
loadChildren: 'app/lazy/right.module#LazyRightModule'
}
]
}];
Run Code Online (Sandbox Code Playgroud)
你MyTabsComponent需要以某种方式展示这一点,如何?以下是Material文档的内容(简化):
<h2>My tabs component</h2>
<nav mat-tab-nav-bar>
<a mat-tab-link routerLink="left">Left tab</a>
<a mat-tab-link routerLink="right">Right tab</a>
</nav>
<router-outlet></router-outlet>
Run Code Online (Sandbox Code Playgroud)
但是如果您有多个选项卡怎么办?好吧,文档是这样说的,我简化了前面的示例:
<a mat-tab-link
*ngFor="let link of navLinks"
routerLinkActive #rla="routerLinkActive"
[routerLink]="link.path"
[active]="rla.isActive">
{{link.label}}
</a>
Run Code Online (Sandbox Code Playgroud)
所以现在,您可以创建几个惰性组件,以及这些惰性路由的路由配置。事实上,您甚至可以创建一个脚本来生成1您的路由配置,甚至作为构建的一部分为您生成那些惰性模块。
1 -角度示意图?
这是假设您知道自己拥有哪些组件。如果您只想让用户在您的文本框中输入内容怎么办?并自己选择任何组件?就像,有一个下拉菜单,让用户决定他们想要的所有选项卡,然后最重要的是,延迟加载它们?
进展如何?首先,你的路线孩子现在有点不同了:
{
path: 'tabs',
component: MyTabsComponent,
children: [{
path: ':tab',
loadChildren: 'app/lazy/lazy.module#LazyWrapperModule',
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您LazyWrapperModule导出一个LazyWrapperComponent. 该组件在模板中有自己的本地路由器出口。它还根据 url 加载组件:
constructor(private route: ActivatedRoute, private router: Router) {}
ngOnInit() {
this.activatedRoute.params.subscribe(params => {
const tab = params.tab;
if (!this.isRouteValid(tab)) {
return this.router.navigate(['error'])
}
this.router.navigate([tab]);
});
}
Run Code Online (Sandbox Code Playgroud)
LazyWrapperModule 也有路由器配置:
@NgModule({
imports: [
RouterModule.forChild([{
path: 'tab1',
component: Tab1
},
{
path: 'tab2',
component: Tab2
},
...
{
path: 'tab100',
component: Tab100
}]
],
...
Run Code Online (Sandbox Code Playgroud)
现在,这看起来好多了。您可以从 TabsModule 导航到任何内容。然后它通过参数加载一个组件。例如,如果用户输入错误的选项卡,您的组件可以显示错误选项卡,或者您可以简单地提供预先输入“允许的”选项卡列表等。有趣的东西!
但是如果您不想限制用户怎么办?您想让他们在该文本框中输入“我的最动态组件”吗?
您可以简单地动态创建一个组件。再次有一个包装器组件来创建和注入组件。例如模板:
<input [(ngModel)]="name" required>
<textrea [(ngModel)]="template">
<button (click)="createTemplate()">Create template</button>
<div #target></div>
Run Code Online (Sandbox Code Playgroud)
那么该组件可以是这样的:
class MyTabsComponent {
@ViewChild('target') target;
name = 'TempComponent';
template: '<span class="red">Change me!</span>';
styles: ['.red { border: 1px solid red; }']
constructor(private compiler: Compiler,
private injector: Injector,
private moduleRef: NgModuleRef<any>) {
}
createTemplate() {
const TempComponent = Component({ this.template, this.styles})(class {});
const TempModule = NgModule({
declarations: [TempComponent]
})(class {});
this.compiler.compileModuleAndAllComponentsAsync(TempModule)
.then((factories) => {
const f = factories.componentFactories[0];
const cmpRef = f.create(this.injector, [], null, this.m);
cmpRef.instance.name = this.name;
this.target.insert(cmpRef.hostView);
});
}
... // other stuff
}
Run Code Online (Sandbox Code Playgroud)
现在,具体如何使用它,取决于您的具体需求。例如,对于家庭作业,您可以尝试动态创建像上面这样的组件,并将其注入到<mat-tab-group>上面的更多内容中。或者,动态创建到现有组件的路由作为延迟加载的链接。或者……可能性。我们爱他们。
| 归档时间: |
|
| 查看次数: |
2297 次 |
| 最近记录: |