Origianl article

Protal from Angular CDK, is a way to create dynammic component.

Consider an example of Page toolbar.

This toolbar should  show differently content when route changed.

For example, when we changed the router to 'Contacts page':

There should be a Mat-icon (Plus icon) showing on the toolbar.

Tradional Approach:

Listening on the route changes and using *ngIf or *ngSwitch to switching template.

This approach works fine for small application, but for large application, switching logic becomes harder to control.

Also 'app-page-actions component' should have no idea 'currently it is in Home page or it is in Contacts page'. In other words, those logic should not be hard code inside the component.

Portal Approach:

To make portal works, it reuqests a host container and a component or a template.

The host container is the placeholder DOM element, this is the place <app-page-acitions> should be rendered into.

  <!-- shell.component.html-->
<div fxFlex="50px" id="page-actions-container">
<!-- content will be placed dynamically via Cdk Portal -->
</div>

(full code see the bottom)

App-page-actions itself can be just a placeholder which implements content projection:

  <ng-template cdk-portal>
<ng-content></ng-content>
</ng-template>

So now its upto each page to tell App-page-actions, whether there is any action or what action to be rendered. For example, the contacts page could be:

<app-page-actions>
<button type="button" class="toolbar-btn" mat-icon-button (click)="onSave()">
<mat-icon>add</mat-icon>
</button>
</app-page-actions>

To connnect portal host and portal component or template:

import {
Component,
OnInit,
AfterViewInit,
ComponentFactoryResolver,
Injector,
ViewContainerRef,
ApplicationRef,
ViewChild,
OnDestroy
} from '@angular/core';
import {
DomPortalHost,
TemplatePortal,
PortalHost,
CdkPortal
} from '@angular/cdk/portal'; @Component({
selector: 'app-page-actions',
template: `
<ng-template cdk-portal>
<ng-content></ng-content>
</ng-template>
`,
styles: []
})
export class PageActionsComponent implements OnInit, AfterViewInit, OnDestroy {
private portalHost: PortalHost;
@ViewChild(CdkPortal) portal; constructor(
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector,
private appRef: ApplicationRef
) {} ngOnInit() {} // We have to wait until DOM is created, so that we can access the DOM element
ngAfterViewInit(): void {
// Create a portalHost from a DOM element
this.portalHost = new DomPortalHost(
document.querySelector('#page-actions-container'), // get the placeholder element by Id
this.componentFactoryResolver, // you have to do this
this.appRef, // you have to do this
this.injector // you have to do this :(
); // Attach portal to host
this.portalHost.attach(this.portal);
} // Always remember to clean up the dynamic component
ngOnDestroy(): void {
this.portalHost.detach();
}
}

That's all.

Well, how to do is not so important, but rather why we should do it.

To summry, portal is good for

1. Better component articulture.

We know that, app-page-actions should have no idea which page current is. It should only receive the component from content projection and display it.   This can be done in Content projection.

2. We have a placeholder where the app-page-actions should be rendered for different pages.

This helps Angular to understand our applications better. (better for AOT)

--------------------------

Layout:

<!-- shell.component.html-->
<mat-sidenav-container class="sidenav-container">
<mat-sidenav #drawer class="sidenav" fixedInViewport="true" [attr.role]="(isHandset$ | async) ? 'dialog' : 'navigation'"
[mode]="(isHandset$ | async) ? 'over' : 'side'" [opened]="!(isHandset$ | async)">
<mat-toolbar color="primary">Menu</mat-toolbar>
<mat-nav-list>
<a mat-list-item routerLink="/home">Home</a>
<a mat-list-item routerLink="/contacts">Contacts</a>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content>
<mat-toolbar color="primary">
<button type="button" aria-label="Toggle sidenav" mat-icon-button (click)="drawer.toggle()" *ngIf="isHandset$ | async">
<mat-icon aria-label="Side nav toggle icon">menu</mat-icon>
</button>
<span>Application Title</span> <div fxFlex fxFill></div>
<div fxFlex="50px" id="page-actions-container">
<!-- content will be placed dynamically via Cdk Portal -->
</div>
</mat-toolbar> <div class="app-container">
<ng-content></ng-content>
</div>
</mat-sidenav-content>
</mat-sidenav-container>

[Angular] Why should we using Protal的更多相关文章

  1. Angular杂谈系列1-如何在Angular2中使用jQuery及其插件

    jQuery,让我们对dom的操作更加便捷.由于其易用性和可扩展性,jQuer也迅速风靡全球,各种插件也是目不暇接. 我相信很多人并不能直接远离jQuery去做前端,因为它太好用了,我们以前做的东西大 ...

  2. Angular企业级开发(5)-项目框架搭建

    1.AngularJS Seed项目目录结构 AngularJS官方网站提供了一个angular-phonecat项目,另外一个就是Angular-Seed项目.所以大多数团队会基于Angular-S ...

  3. TypeScript: Angular 2 的秘密武器(译)

    本文整理自Dan Wahlin在ng-conf上的talk.原视频地址: https://www.youtube.com/watch?v=e3djIqAGqZo 开场白 开场白主要分为三部分: 感谢了 ...

  4. angular实现统一的消息服务

    后台API返回的消息怎么显示更优雅,怎么处理才更简洁?看看这个效果怎么样? 自定义指令和服务实现 自定义指令和服务实现消息自动显示在页面的顶部,3秒之后消失 1. 显示消息 这种显示消息的方式是不是有 ...

  5. div实现自适应高度的textarea,实现angular双向绑定

    相信不少同学模拟过腾讯的QQ做一个聊天应用,至少我是其中一个. 过程中我遇到的一个问题就是QQ输入框,自适应高度,最高高度为3row. 如果你也像我一样打算使用textarea,那么很抱歉,你一开始就 ...

  6. Angular企业级开发-AngularJS1.x学习路径

    博客目录 有链接的表明已经完成了,其他的正在建设中. 1.AngularJS简介 2.搭建Angular开发环境 3.Angular MVC实现 4.[Angular项目目录结构] 5.[SPA介绍] ...

  7. Angular企业级开发(4)-ngResource和REST介绍

    一.RESTful介绍 RESTful维基百科 REST(表征性状态传输,Representational State Transfer)是Roy Fielding博士在2000年他的博士论文中提出来 ...

  8. Angular企业级开发(3)-Angular MVC实现

    1.MVC介绍 Model-View-Controller 在20世纪80年代为程序语言Smalltalk发明的一种软件架构.MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并 ...

  9. Angular企业级开发(2)-搭建Angular开发环境

    1.集成开发环境 个人或团队开发AngularJS项目时,有很多JavaScript编辑器可以选择.使用优秀的集成开发环境(Integrated Development Environment)能节省 ...

随机推荐

  1. 在vue项目npm run build后,index.html中引入css和js 报MIME type问题

    问题: 1.在vue项目中,build打包后,index页面打开会报错, MIME type ('text/html') ;报错内容:because its MIME type ('text/html ...

  2. ACM_梦中的函数

    梦中的函数 Time Limit: 2000/1000ms (Java/Others) Problem Description: 寒假那段时间,每天刷题的小G连做梦都是代码,于是有了这道题. 给定一个 ...

  3. VS插件-Resharper

    最近代码因为Resharper出现了点问题,同事问我这个插件有什么用,下面就列几个最近常用的功能.其他功能后续慢慢更新 1.什么是Resharper ReSharper是一个JetBrains公司出品 ...

  4. Ubuntu 系统的常用快捷键

    Ubuntu操作基本快捷键 ibus-setup :设置系统输入法 scp filename username@serverIp:/home/xxx/xxx/filename   回车输入该usern ...

  5. JS——属性绑定

    1.普通形式 <script> var stu = new Object(); stu.name = "ww"; console.log(stu);//{name: & ...

  6. 如何在eclipse中设置断点并调试程序

    eclipse导入源码后可以看见代码但并不能调试,(解决方法) 1.eclipse默认的运行环境不是jdk中的jre.将jre换成jdk: 2. 先去掉勾,apply,在打上勾,apply 参考:ht ...

  7. 使用码云gitee.com托管代码

    1.新建项目 可以看到团队资源管理器是这样的,已经在本地有存储库,所有更改可以保存本地 2.在码云上新建项目 项目名称必填,其它项根据情况填写 3.复制项目地址关联到本地存储库 填写码云的项目地址,发 ...

  8. GCD & Operation queues & Thread

    One of the technologies for starting tasks asynchronously is Grand Central Dispatch (GCD). This tech ...

  9. 查询数据表行数 然后循环查找表 添加数据到ITEMS

    ;i<tbBiao.Rows.Count;i++) { string TableName = (tbBiao.Rows[i]["Table"]).ToString(); tb ...

  10. CAD在网页中绘制批注

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 3 ...