Angular 2:从组件实例获取格式化模板?

时间:2016-04-13 10:31:31

标签: javascript angular

上下文

我正在使用Angular 2,TypeScript,@ ngrx / store和SystemJS开展项目。我已经构建了一个模块加载器,因此我可以通过组装模块来构建我的应用程序我将首先向您展示的是主模块,它提供了我的应用程序的根目录(导航,路由器,子区域和内容区域)。

在进一步说明之前,我将解释我拥有什么,想要什么以及为什么。检查此屏幕截图:

graphics

您可以看到不同的页面(帐户,频道,播放列表...)。这些页面列在 mainNav 中。每个页面都会提供一个子菜单(在这种情况下名为 sidenav )和内容。这是我所知道的非常常见的设计:)。

让我们走得更远。我有一个名为 MainComponent 的主要角度组件。这是我的根本组成部分。

main.component.ts

@Component({
    selector: 'app-view',
    directives: [ Devtools, MainNavComponent, SidenavLayoutComponent ],
    template: `
        <ngrx-devtools *ngIf="prodEnv === false"></ngrx-devtools>
        <cmp-main-nav></cmp-main-nav>
        <cmp-main-layout [prodEnv]="prodEnv"></cmp-main-layout>
    `
})
@RouteConfig([
    { path: '/home',    name: 'Home',   component: HomeComponent,   useAsDefault: true },
    { path: '/medias',  name: 'Medias', component: MediasComponent },
])
export class MainComponent {
    private prodEnv: boolean = initialState.prodEnv;

    constructor (private _router:Router, private _store:Store<AppStore>) {
        _router.subscribe(url => _store.dispatch(changeUrl(url)));
    }
}

让我们看看 MainNavComponent ,显然......渲染 mainNav 部分。

mainNav.component.ts

@Component({
    selector: 'cmp-main-nav',
    directives: [ ROUTER_DIRECTIVES, MainLinkComponent ],
    styleUrls: ['src/modules/component@main/src/styles/mainNav.css'],
    template: `
        <nav class="main-nav">
            <ul>
                <cmp-main-link [routeName]="['Home']" [icon]="'face'">Account</cmp-main-link>
                <cmp-main-link [routeName]="['Home']" [icon]="'face'">Channel</cmp-main-link>
                <cmp-main-link [routeName]="['Home']" [icon]="'face'">Playlist</cmp-main-link>
                <cmp-main-link [routeName]="['Home']" [icon]="'face'">Medias</cmp-main-link>
                <cmp-main-link [routeName]="['Home']" [icon]="'face'">Security</cmp-main-link>
            </ul>                    
        </nav>
    `
})
export class MainNavComponent { }

最后, sidenavLayout.component.ts angular material component sidenav 包裹在内,并使用router-outlet显示主机组件提供的内容(参见 main.component.ts

@Component({
    selector: 'cmp-main-layout',
    directives: [ /* ... */ ],
    styleUrls: [ /* ... */ ],
    template: `
        <md-sidenav-layout [style.right]="prodEnv ? '' : '30%'" class="sidenav-layout-wrapper">            
            <md-sidenav class="sidenav" mode="side" [opened]="sidenavIsOpened">
                <ul>
                    <li><cmp-sidenav-link [icon]="'home'" [routeName]="['Home']">Home</cmp-sidenav-link></li>
                    <li><cmp-sidenav-link [icon]="'input'" [routeName]="['Medias']">Médias</cmp-sidenav-link></li>
                </ul>

                <button md-button (click)="closeSidenav()">CLOSE</button>
            </md-sidenav>

            <button md-button (click)="openSidenav()">OPEN</button>
            <router-outlet></router-outlet>
        </md-sidenav-layout>
    `
})
export class SidenavLayoutComponent {
    /* ... */
}

你想要什么?

我之前说我已经构建了一个模块加载器。我希望我的页面(帐户,频道......)成为模块。所以一个“模块”为我提供了:

  • sidenav内容(是的,页面有不同的侧边栏)
  • 一个内容(它将被放入绿色内容区域内)

目前,我的所有应用中的侧边栏都是相同的。我正在寻找一种能够根据页面更新侧边栏的方法。

你有什么尝试?

我试图删除SidenavLayoutComponent。页面(例如帐户)为我提供AccountComponent。该组件包含sidenav和内容。然后,我可以在我的 main.component.ts 中通过AccountComponent添加<router-outlet>

但是没有:我说我想在我的sidenav中加入一些通用的东西。我需要将这个通用内容放在每个模块(页面)上。我真的想要一个'root'sidenav。然后模块将内容放在中。 (还有其他原因,但没关系)。

你想要什么?

看看这段代码。它必须在SidenavLayoutComponent类中:

updateSidenavContent() { 
    // @todo : retrieve the template of the host component (from the _router) and insert it into the template.
    // Maybe using this :
    // this._router._outlet._componentRef.__zone_symbol__value.instance
}

constructor (private _router:Router) {
    // only if the host component have changed :)
    this._router.subscribe(route => this.updateSidenavContent()); 
}

我想从实例(或类,但这很奇怪)获取表示组件模板的格式化字符串。

所有这些阅读都要问这个问题?!

我真的怀疑像这样检索模板是一个解决方案。所以我提出了我的案例,让你能够找到另一种解决方案,也许更好。

我对Angular 2比较陌生,所以也许我错过了一些重要的东西。

我不想向你展示我的所有环境,这个“模块加载器”可能很奇怪。我想我们需要知道的就是这里。

谢谢!

1 个答案:

答案 0 :(得分:1)

如果要动态添加组件,请使用DynamicComponentLoader

如果在您的示例中有用,可以使用DI配置要插入的组件。

 bootstrap(AppComponent, [provide('navComponent', {useValue: SomeNavComponent})]);

然后请求

class AppComponent {
  constructor(@Inject('navComponent') private navComponent, 
       private dcl:DynamicComponentLoader, private elementRef:ElementRef) {}

  ngOnInit() {
    this.dcl.load...
  }
}

提示:[OpaqueToken]](https://angular.io/docs/ts/latest/api/core/OpaqueToken-class.html)应优先于DI键的普通字符串。

您还可以根据配置值动态加载具有不同路由(和不同组件)的路由。