【问题标题】:Angular 2 : get formatted template from a component instance?Angular 2:从组件实例获取格式化模板?
【发布时间】:2016-08-04 09:20:47
【问题描述】:

上下文

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

在继续深入之前,我将解释我拥有什么、我想要什么以及为什么。检查此屏幕截图:

您可以看到不同的页面(帐户、频道、播放列表...)。这些页面列在 ma​​inNav 中。每个页面都提供一个子菜单(在本例中名为 sidenav)和一个内容。我知道这是一个很常见的设计:)。

让我们更深入。我有一个名为 MainComponent 的主要角度组件。这是我的根组件。

ma​​in.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 显然...渲染 ma​​inNav 部分。

ma​​inNav.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.tssidenav 包裹在 angular material component 内,并使用 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 和内容。然后,我可以通过&lt;router-outlet&gt; 将这个AccountComponent 包含在我的ma​​in.component.ts 中。

但是不:假设我想在我的 sidenav 中放入一些通用的东西。我需要把这个通用内容放在每个 modules(页面)上。我真的很想拥有一个 '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 比较陌生,所以也许我错过了一些重要的东西。

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

谢谢!

【问题讨论】:

  • 我知道this answer。但我不知道是否可以动态添加directives。我不这么认为。 编辑: 如果我使用_router,也许我不需要指令。我正在尝试这个。

标签: javascript angular


【解决方案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 密钥的纯字符串。

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

【讨论】:

  • 非常感谢。就我而言,使用 DI 会很棘手。检查这个:this._router._outlet._componentRef.__zone_symbol__value.hostComponent。通常,_outlet 是私有的。那么您知道一种无需调用私有属性即可获取主机组件的方法吗?
猜你喜欢
  • 1970-01-01
  • 2016-04-21
  • 1970-01-01
  • 2017-07-15
  • 1970-01-01
  • 2016-04-29
  • 1970-01-01
  • 2019-05-12
  • 2021-11-25
相关资源
最近更新 更多