angular2笔记--模板语法

小弟初学angular2,借花献佛,大神勿喷,只是笔记

写视图的模板都需要什么,我们将覆盖模板语法中的下列基本元素:
HTML
插值表达式 Interpolation
模板表达式 Template expressions
模板语句 Template statements
绑定语法
属性绑定
HTML属性、class和style绑定
事件绑定 Event binding
使用NgModel进行双向数据绑定
内置命令:
    NgClass
    NgStyle
    NgIf
    NgSwitch
    NgFor
*与<template>
模板引用变量
输入与输出属性 Input and output
模板表达式操作符:
    管道 pipe |
    安全导航操作符 ?.
------------------------------------------
2.插值表达式:双花括号{{}}
    <h3>
        {{title}}
        <img src="{{heroImageUrl}}" style="height:30px">
    </h3>
    <p>The sum of 1+1 is {{1+1}}</p>
    还可以调用方法:其中getVal()是所属组件中的方法
    <p>The sum of 1+1 is not {{1+1+getVal()}}</p>
    注意:计算模板表达式有
---------------------------------------
3.模板表达式:
    [property]="expression"
------------------------------------------
4.模板语句
    (event)="statement"
    (click)="onSave()"
-------------------------------------------
5.绑定语法
    单向:从数据源到视图目标    
        {{expression}}
        [target] = "expression"
        bind-target = "expression"
    单向:从视图目标到数据源
        (target) = "statement"
        on-target = "statement"
    双向:
        [(target)] = "expression"
        bindon-target= "expression"
    
    注意:要理解angular绑定如何工作,必须清楚HTML Attribute和DOM Property区别
        attribute(下简称a)是由HTML定义的,property(下简称p)是由DOM定义的
        1)少量的a和p之间有1:1的映射,比如id
        2)有些a没有对应p,比如colspan
        3)有些p没有对应a,比如textContent
    原则:a初始化p,p的值可以变,a的值不能变;
          a值指定了初始值,p值是当前值
    最重要:模板绑定是通过property和事件来工作的,不关attribute的事
            在angular2中,attribute的唯一作用是初始化元素和指令的状态,然后就完全靠边站了,
            当进行数据绑定时,只是在与元素和指令的property和事件打交道
        
----------------------------------------------------------------
6.属性绑定
    当要把一个视图元素的属性设置为模板表达式时,我们就要写模板的属性绑定
    最常用的是把元素的属性设置为组件中属性的值,
    下面image元素的src属性会被绑定到组件的heroImageUrl属性上:
    <img [src]="heroImageUrl">等价于<img bind-src="heroImageUrl">
    下面这是当组件isUnChanged(未改变)时禁用一个按钮:
    <button [disabled]="isUnchanged" > Cancel is disabled</button>
    这是设置指令的属性:
    <div [ngClass]="classes" >[ngClass] binding to the classes property</div>
    这是设置一个自定义组件的模型属性,这是父子组件之间通讯的重要途径
    <hero-detail [hero]="currentHero"></hero-detail>
-------------------------------------------------
    多数情况下,我们既可以使用插值表达式,也可以使用属性绑定,但是建议使用可读性强的插值表达式
    
    我们可以通过Attribute绑定来直接设置Attribute的值。
    这是“绑定到目标属性”这条规则中唯一的例外。这是唯一的一个能创建和设置Attribute的绑定形式。
    因为当元素没有属性可绑的时候,我们不得不使用Attribute绑定。
    如果我们想写出类似下面这样的东西,这一现状会令我们痛苦
    <tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
    我们会得到这个错误:
    Template parse errors:
    Can't bind to 'colspan' since it isn't a known native property

    模板解析错误:不能绑定到'colspan',因为它不是已知的原生属性
    正如提示中所说,<td>元素没有colspan属性。
    但是插值表达式和属性绑定只能设置属性,而不是Attribute
    我们需要Attribute绑定来创建和绑定到这样的Attribute
    Attribute绑定在语法上类似于属性绑定。
    但方括号中的部分不是一个元素的属性名,而是由一个attr前缀,紧跟着一个点(.),再跟着Attribute的名字组成。
    我们可以通过一个能求值为字符串的表达式来设置Attribute的值。
    这里我们把[attr.colspan]绑定成一个通过计算得到的值:
    <table border=1>
        <!--  expression calculates colspan=2 -->
        <tr><td [attr.colspan]="1 + 1">One-Two</td></tr>

        <!-- ERROR: There is no `colspan` property to set!
            <tr><td colspan="{{1 + 1}}">Three-Four</td></tr>
        -->

        <tr><td>Five</td><td>Six</td></tr>
    </table>
------------------------------------------------------
7.css绑定(属于属性绑定)
    CSS类绑定在语法上类似于属性绑定。但方括号中的部分不是一个元素的属性名,
    而是包括一个class前缀,紧跟着一个点(.),再跟着CSS类的名字组成。
    其中后两部分是可选的。形如:[class.class-name]
    下列例子示范了如何通过CSS类绑定来添加和移除应用的"special"类。不用绑定直接设置Attribute时是这样的:
    <div class="bad curly special">Bad curly special</div>
    我们可以把它改写为一个绑定到所需CSS类名的绑定;这是一个或者全有或者全无的替换型绑定
    (译注:即当badCurly有值时class这个Attribute设置的内容会被完全覆盖)。
    <div class="bad curly special" [class]="badCurly">Bad curly</div>
    最后,我们可以绑定到一个特定的类名。
    当模板表达式的求值结果是真值时,Angular会添加这个类,反之则移除它
    <!-- toggle the "special" class on/off with a property -->
    <div [class.special]="isSpecial">The class binding is special</div>

    <!-- binding to `class.special` trumps the class attribute -->
    <div class="special"
     [class.special]="!isSpecial">This one is not so special</div
    虽然这是一个切换单一类名的好办法,但我们通常更喜欢使用NgClass指令来同时管理多个类名。
----------------------------------------------------------
8.style样式绑定(属性绑定)
    <button [style.color] = "isSpecial ? 'red': 'green'">Red</button>
    <button [style.background-color]="canSave ? 'cyan': 'grey'" >Save</button>
    有些样式绑定中的样式带有单位。在这里,我们可以根据条件用“em”和“%”来设置字体大小的单位。
    <button [style.font-size.em]="isSpecial ? 3 : 1" >Big</button>
    <button [style.font-size.%]="!isSpecial ? 150 : 50" >Small</button>
    虽然这是一个设置单一样式的好办法,但我们通常更喜欢使用NgStyle指令来同时设置多个内联样式
--------------------------------------------------------------
9.event事件绑定
    我们前面遇到过的那些绑定的数据流都是单向的:从组件到元素。
    用户不会只盯着屏幕看。它们会在输入框中输入文本。它们会从列表中选取条目。
    它们会点击按钮。这类用户动作可能导致反向的数据流:从元素到组件。
    知道用户动作的唯一方式是监听正确的事件,比如击键、鼠标移动、点击和触屏。
    我们可以通过Angular的事件绑定来定义我们对哪些用户动作感兴趣。
    事件绑定语法由等号左侧带圆括号的目标事件,和右侧一个引号中的模板语句组成。
    下列事件绑定监听按钮的点击事件。无论什么时候,发生点击时,都会调用组件的onSave()方法
    <button (click)="onSave()">Save</button>
    目标事件:
        圆括号中的名称 —— 比如(click) —— 标记出了目标事件。在下面这个例子中,目标是按钮的click事件
        <button (click)="onSave()">Save</button>等价于<button on-click="onSave()">On Save</button>
    元素事件可能是更常见的目标,但Angular会先看这个名字是否能匹配上已知指令的事件属性,就像下面这个例子
    <div (myClick)="clickMessage=$event">click with myClick</div>
    $event和事件处理语句
        在事件绑定中,Angular会为目标事件设置事件处理器
        当事件发生时,这个处理器会执行模板语句。
        典型的模板语句通常涉及到那些针对事件想作出相应处理的接收器,
        例如从一个HTML控件中取得一个值,并存入一个模型。
        这种绑定会通过一个名叫$event的事件对象传达关于此事件的信息(包括数据值)
        事件对象的形态取决于目标事件。如果目标事件是一个原生DOM元素事件,
        $event就是一个DOM事件对象,它有像target和target.value这样的属性。
        <input [value]="currentHero.firstName"
            (input)="currentHero.firstName=$event.target.value" >
            我们在把输入框的value绑定到firstName属性,并且我们正在通过绑定到输入框的input事件来监听更改。
            当用户造成更改时,input事件被触发,并且在一个包含了DOM事件对象的$event的上下文中执行这条语句
            要更改firstName属性,就要通过路径$event.target.value来获取更改后的值
--------------------------------------------
10.使用NgModel进行双向数据绑定
    当开发数据输入表单时,我们通常希望既显示数据的属性,也在用户修改时更新那个属性
    [(NgModel)]双向数据绑定语法让它变得简单,这里是例子:
    <input [(ngModel)]="currentHero.firstName">
    要使用ngModel做双向数据绑定,得先把FormsModule导入我们的模块并把它加入NgModule装饰器的imports数组。
    ---------app.module.ts
    import { NgModule } from '@angular/core';
    import { BrowserModule }  from '@angular/platform-browser';
    import { FormsModule } from '@angular/forms';

    import { AppComponent } from './app.component';

    @NgModule({
        imports: [
            BrowserModule,
            FormsModule
        ],
        declarations: [
            AppComponent
        ],
        bootstrap: [ AppComponent ]
    })
    export class AppModule { }

-----------------------------------------------------------
11.内置指令
    1)NgClass
        我们经常用动态添加或删除CSS类的方式来控制元素如何显示。
        通过绑定到NgClass,我们可以同时添加或移除多个类。
        CSS类绑定是添加或删除单个类的最佳途径。
        <div [class.special]="isSpecial">The class binding is special</div>
        当我们想要同时添加或移除多个CSS类时,NgClass指令可能是更好的选择
        绑定到一个 key:value 形式的控制对象,是应用NgClass的好方式。
        这个对象中的每个key都是一个CSS类名,如果它的value是true,这个类就会被加上,否则就会被移除。
        setClasses() {
            let classes =  {
                saveable: this.canSave,      // true
                modified: !this.isUnchanged, // false
                special: this.isSpecial,     // true
            };
            return classes;
        }
        现在,我们可以添加一个NgClass属性绑定,它会调用setClasses,并据此设置元素的类:
        <div [ngClass]="setClasses()">This div is saveable and special</div>
    2)NgStyle
        我们可以基于组件的状态动态设置内联样式。
        绑定到NgStyle可以让我们同时设置很多内联样式。
        样式绑定是设置单一样式值的简单方式。
        <div [style.font-size]="isSpecial ? 'x-large' : 'smaller'" >
            This div is x-large.
        </div>
        如果我们要同时设置多个内联样式,NgStyle指令可能是更好的选择。
        我们通过把它绑定到一个 key:value 控制对象的形式使用NgStyle。
        对象的每个key是样式名,它的value就是能用于这个样式的任何值。
        考虑一个类似于setStyles的组件方法,它返回一个定义三种样式的对象
        setStyles() {
            let styles = {
                // CSS property names
                'font-style':  this.canSave      ? 'italic' : 'normal',  // italic
                'font-weight': !this.isUnchanged ? 'bold'   : 'normal',  // normal
                'font-size':   this.isSpecial    ? '24px'   : '8px',     // 24px
            };
            return styles;
        }
        现在我们添加一个NgStyle属性绑定,让它调用setStyles,并据此设置元素的样式
        <div [ngStyle]="setStyles()">
            This div is italic, normal weight, and extra large (24px).
        </div>
    3)NgIf
        通过把NgIf指令绑定到一个真值表达式,我们可以把一个元素的子树(元素及其子元素)添加到DOM上
        <div *ngIf="currentHero">Hello, {{currentHero.firstName}}</div>
        绑定到一个假值表达式将从DOM中移除元素的子树。
        <!-- because of the ngIf guard
            `nullHero.firstName` never has a chance to fail -->
        <div *ngIf="nullHero">Hello, {{nullHero.firstName}}</div>

        <!-- Hero Detail is not in the DOM because isActive is false-->
        <hero-detail *ngIf="isActive"></hero-detail>
        可见性和NgIf不是一回事
        我们可以通过类绑定或样式绑定来显示和隐藏一个元素的子树(元素及其子元素)。
        <!-- isSpecial is true -->
        <div [class.hidden]="!isSpecial">Show with class</div>
        <div [class.hidden]="isSpecial">Hide with class</div>

        <!-- HeroDetail is in the DOM but hidden -->
        <hero-detail [class.hidden]="isSpecial"></hero-detail>

        <div [style.display]="isSpecial ? 'block' : 'none'">Show with style</div>
        <div [style.display]="isSpecial ? 'none'  : 'block'">Hide with style</div>
        隐藏一个子树和用NgIf排除一个子树是截然不同的。
        当我们隐藏一个子树时,它仍然留在DOM中。
        子树中的组件及其状态仍然保留着。
        即使对于不可见属性,Angular也会继续检查变更。
        子树可能占用相当可观的内存和运算资源。
        当NgIf为false时,Angular从DOM中实际移除了这个元素的子树。
        它销毁了子树中的组件及其状态,也潜在释放了可观的资源,最终让用户体验到更好的性能。
        显示/隐藏技术用在小型元素树上可能还不错。
        但在隐藏大树时我们得小心;NgIf可能是更安全的选择。但要记住:永远得先测量,再下结论。
    4)NgSwitch
        当需要从一组可能的元素树中根据条件显示一个时,我们就把它绑定到NgSwitch。
        Angular将只把选中的元素树放进DOM中。
        <span [ngSwitch]="toeChoice">
            <span *ngSwitchCase="'Eenie'">Eenie</span>
            <span *ngSwitchCase="'Meanie'">Meanie</span>
            <span *ngSwitchCase="'Miney'">Miney</span>
            <span *ngSwitchCase="'Moe'">Moe</span>
            <span *ngSwitchDefault>other</span>
        </span>
        我们把作为父指令的NgSwitch绑定到一个能返回开关值的表达式。
        本例中,这个值是字符串,但它也可能是任何类型的值。
        这个例子中,父指令NgSwitch控制一组<span>子元素。
        每个<span>或者挂在一个匹配值表达式上,或者被标记为默认情况
        任何时候,这些span中最多只有一个会出现在DOM中.
        如果这个span的匹配值与开关值相等,Angular就把这个<span>添加到DOM中。
        如果没有任何span匹配上,Angular就把默认的span添加到DOM中。
        Angular会移除并销毁所有其它的span。
        我们可以用任何其它元素代替本例中的span。
        那个元素可以是一个带有巨大子树的<div>。
        只有匹配的<div>和它的子树会显示在DOM中,其它的则会被移除。
        这里有三个相互合作的指令:
            ngSwitch:绑定到一个返回开关值的表达式
            ngSwitchCase:绑定到一个返回匹配值的表达式
            ngSwitchDefault:一个用于标记出默认元素的Attribute
        不要在ngSwitch的前面放星号(*),而应该用属性绑定。
        要把星号(*)放在ngSwitchCase和ngSwitchDefault的前面
    5)NgFor
        NgFor是一个重复器指令 —— 自定义数据显示的一种方式。
        我们的目标是展示一个由多个条目组成的列表。我们定义了一个HTML块,它规定了单个条目应该如何显示。
        我们告诉Angular把这个块当做模板,渲染列表中的每个条目
        <div *ngFor="let hero of heroes">{{hero.fullName}}</div>
        我们也可以把NgFor应用在一个组件元素上,就像这个例子中一样:
        <hero-detail *ngFor="let hero of heroes" [hero]="hero"></hero-detail>
------------------------------------------------------
12. *与<template>
    1)展开*ngIf
        当我们审视NgFor、NgIf和NgSwitch内置指令时,我们使用了一种古怪的语法:出现在指令名称前面的星号(*)。
        *是一种语法糖,它让那些需要借助模板来修改HTML布局的指令更易于读写。
        NgFor、NgIf和NgSwitch都会添加或移除元素子树,这些元素子树被包裹在<template>标签中。
        我们没有看到<template>标签,那是因为这种*前缀语法让我们忽略了这个标签,
        而把注意力直接聚焦在所要包含、排除或重复的那些HTML元素上。
        我们可以像Angular一样,自己把*前缀语法展开成template语法,这里是*ngIf的一些代码:
        <hero-detail *ngIf="currentHero" [hero]="currentHero"></hero-detail>
        currentHero被引用了两次,第一次是作为NgIf的真/假条件,第二次把实际的hero值传给了HeroDetailComponent。
        展开的第一步是把ngIf(没有*前缀)和它的内容传给一个表达式,再赋值给template指令。
        <hero-detail template="ngIf:currentHero" [hero]="currentHero"></hero-detail>
        下一步,也就是最后一步,是把HTML包裹进<template>标签和一个[ngIf]属性绑定中:
        <template [ngIf]="currentHero">
            <hero-detail [hero]="currentHero"></hero-detail>
        </template>
        注意,[hero]="currengHero"绑定留在了模板中的子元素<hero-detail>上。
        不要误写为ngIf="currentHero"!
        这种语法会把一个字符串"currentHero"赋值给ngIf。
        在JavaScript中,非空的字符串是真值,所以ngIf总会是true,
        而Angular将永远显示hero-detail…… 即使根本没有currentHero
    2)展开*ngSwitch
        类似的转换也作用于*ngSwitch上。我们可以自己解开这个语法糖。
        这里是一个例子,首先是*ngSwitchCase和*ngSwitchDefault,然后再解出<template>标签:
        <span [ngSwitch]="toeChoice">
            <!-- with *NgSwitch -->
            <span *ngSwitchCase="'Eenie'">Eenie</span>
            <span *ngSwitchCase="'Meanie'">Meanie</span>
            <span *ngSwitchCase="'Miney'">Miney</span>
            <span *ngSwitchCase="'Moe'">Moe</span>
            <span *ngSwitchDefault>other</span>

            <!-- with <template> -->
            <template [ngSwitchCase]="'Eenie'"><span>Eenie</span></template>
            <template [ngSwitchCase]="'Meanie'"><span>Meanie</span></template>
            <template [ngSwitchCase]="'Miney'"><span>Miney</span></template>
            <template [ngSwitchCase]="'Moe'"><span>Moe</span></template>
            <template ngSwitchDefault><span>other</span></template>
        </span>
        *ngSwitchWhen和*ngSwitchDefault用和*ngIf完全相同的方式展开,把它们以前的元素包裹在<template>标签中。
        现在,我们应该明白为什么ngSwitch本身不能用星号(*)前缀的原因了吧?
        它没有定义内容,它的工作是控制一组模板.
        上面这种情况下,它管理两组NgSwitchCase和NgSwitchDefault指令,
        一次是(*)前缀的版本,一次是展开模板后的版本
    3)展开*ngFor
        *ngFor要经历类似的转换。我们从一个*ngFor的例子开始:
        <hero-detail *ngFor="let hero of heroes; trackBy:trackByHeroes" [hero]="hero"></hero-detail>
        这里是在把ngFor传进template指令后的同一个例子
        <hero-detail template="ngFor let hero of heroes; trackBy:trackByHeroes" [hero]="hero"></hero-detail>
        这里,它被进一步扩展成了包裹着原始<hero-detail>元素的<template>标签:
        <template ngFor let-hero [ngForOf]="heroes" [ngForTrackBy]="trackByHeroes">
            <hero-detail [hero]="hero"></hero-detail>
        </template>
        NgFor的代码相对NgIf更复杂一点,因为一个重复器有更多活动部分需要配置。
        这种情况下,我们不得不记着为用于标记列表的NgForOf指令和NgForTrackBy指令的进行新建和赋值操作。
        使用*ngFor语法比直接写这些展开后的HTML本身要简单多了。
------------------------------------------------------------
13.模板引用变量
    模板引用变量是模板中对DOM元素或指令的引用。
    它能在原生DOM元素中使用,也能用于Angular组件 —— 实际上,它可以和任何自定义Web组件协同工作。
    引用一个模板引用变量
    我们可以在同一元素、兄弟元素或任何子元素中引用模板引用变量。
    这里是关于创建和消费模板引用变量的另外两个例子
    <!-- phone refers to the input element; pass its `value` to an event handler -->
    <input #phone placeholder="phone number">
    <button (click)="callPhone(phone.value)">Call</button>

    <!-- fax refers to the input element; pass its `value` to an event handler -->
    <input ref-fax placeholder="fax number">
    <button (click)="callFax(fax.value)">Fax</button>
    "phone"的(#)前缀意味着我们将要定义一个phone变量。
    有些人不喜欢使用#字符,而是使用它的规范形式:ref-前缀。例如,我们既能用#phone,也能用ref-phone来定义我们的phone变量。
    如何获取变量的值
    Angular把这种变量的值设置为它所在的那个元素。
    我们在这个input元素上定义了这些变量。
    我们把那些input元素对象传给button元素,在这里,它们被当做参数传给了事件绑定中的call方法。
    NgForm和模板引用变量
    让我们看看最后一个例子:一个表单,使用模板引用变量的典范。
    正如我们在表单一章中所见过的,此表单的HTML可以做得相当复杂。
    下面是一个简化过的范例 —— 虽然仍算不上多简单。
    <form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm">
        <div class="form-group">
            <label for="name">Name</label>
            <input class="form-control" name="name" required [(ngModel)]="currentHero.firstName">
        </div>
        <button type="submit" [disabled]="!theForm.form.valid">Submit</button>
    </form>
    模板引用变量theForm在这个例子中出现了三次,中间隔着一大段HTML。
    <form (ngSubmit)="onSubmit(theForm)" #theForm="ngForm">
        <button type="submit" [disabled]="!theForm.form.valid">Submit</button>
    </form>
    theForm变量的值是什么?
    如果Angular没有接管它,那它可能是个HTMLFormElement。
    实际上它是个ngForm,一个对Angular内置指令NgForm的引用。
    它包装了原生的HTMLFormElement并赋予它更多“超能力”,比如跟踪用户输入的有效性。
    这解释了我们该如何通过检查theForm.form.valid来禁用提交按钮,
    以及如何把一个信息量略大的对象传给父组件的onSubmit方法
    (译注:onSubmit方法可能会出发一个事件,被父组件监听,参见下面的输入和输出属性和父组件监听子组件的事件)。
---------------------------------------------------------------
14.输入与输出属性
    迄今为止,我们主要聚焦在绑定声明的右侧,学习如何在模板表达式和模板语句中绑定到组件成员上。
    当一个成员出现在这个位置上,则称之为数据绑定的源。
    这一节则专注于绑定到的目标,它位于绑定声明中的左侧。
    这些指令的属性必须被声明成输入或输出。
    记住:所有组件皆为指令。
    我们要重点突出下绑定目标和绑定源的区别。
    绑定的目标是在=左侧的部分,源则是在=右侧的部分。
    绑定的目标是绑定符:[]、()或[()]中的属性或事件名,源则是引号(" ")中的部分或插值符号({{}})中的部分。
    源指令中的每个成员都会自动在绑定中可用。
    我们不需要特别做什么,就能在模板表达式或语句中访问指令的成员。
    访问目标指令中的成员则受到限制。
    我们只能绑定到那些显式标记为输入或输出的属性
    在下面的例子中,iconUrl和onSave是组件的成员,它们在=右侧引号中的语法中被引用了。
    <img [src]="iconUrl"/>
    <button (click)="onSave()">Save</button>
    它们既不是组件的输入也不是输出。它们是绑定的数据源。
    现在,看看HeroDetailComponent,它是绑定的目标。
    <hero-detail [hero]="currentHero" (deleteRequest)="deleteHero($event)"></hero-detail>
    HeroDetailComponent.hero和HeroDetailComponent.deleteRequest都在绑定声明的左侧。
    HeroDetailComponent.hero在方括号中,它是一个属性绑定的目标。
    HeroDetailComponent.deleteRequest在圆括号中,它是一个事件绑定的目标
    声明输入和输出属性:
        目标属性必须被显式的标记为输入或输出
        当我们深入HeroDetailComponent内部时,就会看到这些属性被装饰器标记成了输入和输出属性。
        @Input()  hero: Hero;
        @Output() deleteRequest = new EventEmitter<Hero>();
        另外,我们还可以在指令元数据的inputs或outputs数组中标记出这些成员。比如这个例子
        @Component({
            inputs: ['hero'],
            outputs: ['deleteRequest'],
        })
        我们既可以通过装饰器,又可以通过元数据数组来指定输入/输出属性。但别同时用!
-------------------------------------------------------------------
15.模板表达式操作符
    模板表达式语言使用了JavaScript语法的一个子集,并补充了几个用于特定场景的特殊操作符。
    这里我们讲其中的两个:管道和安全导航操作符。
    1)管道操作符( | )
        在用到绑定中之前,表达式的结果可能需要一些转换。比如,我们可能希望把一个数字显示成金额、
        强制文本变成大写,或者过滤一个列表以及排序它.
        Angular管道对像这样的小型转换来说是个明智的选择。
        管道是一个简单的函数,它接受一个输入值,并返回转换结果。
        它们很容易用于模板表达式中,只要使用管道操作符(|)就行了。
        <div>Title through uppercase pipe: {{title | uppercase}}</div>
        管道操作符会把它左侧的表达式结果传给它右侧的管道函数。
        我们还可以通过多个管道串联出表达式:
        <!-- Pipe chaining: convert title to uppercase, then to lowercase -->
        <div>
            Title through a pipe chain:
            {{title | uppercase | lowercase}}
        </div>
        我们还能对它们使用参数:
        <!-- pipe with configuration argument => "February 25, 1970" -->
        <div>Birthdate: {{currentHero?.birthdate | date:'longDate'}}</div>
        json管道是特别设计来帮助我们调试绑定的:
        <div>{{currentHero | json}}</div>
        它生成的输出是类似于这样的:
        { "firstName": "Hercules", "lastName": "Son of Zeus",
            "birthdate": "1970-02-25T08:00:00.000Z",
            "url": "http://www.imdb.com/title/tt0065832/",
            "rate": 325, "id": 1 }
    2)安全导航操作符( ?. )和空属性路径
        Angular的安全导航操作符(?.)是一种流畅而便利的方式,用来保护出现在属性路径中null和undefined值。
        这意味着,当currentHero为空时,保护视图渲染器,让它免于失败
        The current hero's name is {{currentHero?.firstName}}
        我们来详细阐述一下这个问题和解决方案:
        如果下列数据绑定中title属性为空,会发生什么?
        The title is {{title}
        这个视图仍然被渲染出来,但是显示的值是空;我们只能看到“The title is”,
        它后面却没有任何东西。这是合理的行为。至少应用没有崩溃。
        假设模板表达式需要一个属性路径,在下一个例子中,我们要显示一个空(null)英雄的firstName
        The null hero's name is {{nullHero.firstName}}
        JavaScript抛出了一个空引用错误,Angular也是如此:
        TypeError: Cannot read property 'firstName' of null in [null].
        晕,整个视图都不见了。
        如果确信hero属性永远不可能为空,我们就可以声称这是一个合理的行为。
        如果它必须不能为空,但它仍然是空值,我们就制造了一个编程错误,以便它被捕获和修复。
        这种情况下,抛出一个异常正是我们应该做的。
        另一方面,属性路径中的空值可能会时常发生,特别是当我们知道这些数据最终总会到来的时候
        当我们等待数据的时候,视图渲染器不应该抱怨,
        而应该把这个空属性路径显示为空白,就像上面title属性所做的那样。
        不幸的是,当currentHero为空的时候,我们的应用崩溃了。
        我们可以通过写NgIf代码来解决这个问题。
        <!--No hero, div not displayed, no error -->
        <div *ngIf="nullHero">The null hero's name is {{nullHero.firstName}}</div>
        或者我们可以尝试通过&&来把属性路径的各部分串起来,让它在遇到第一个空值的时候,就返回空
        这些方法都有价值,但是会显得笨重,特别是当这个属性路径非常长的时候。
        想象一下在一个很长的属性路径(如a.b.c.d)中对空值提供保护。
        Angular安全导航操作符(?.)是在属性路径中保护空值的一个更加流畅、便利的方式。
        表达式会在它遇到第一个空值的时候跳出。
        显示是空的,但是应用正常工作,而没有发生错误
        <!-- No hero, no problem! -->
        The null hero's name is {{nullHero?.firstName}}
        在像a?.b?.c?.d这样的长属性路径中,它工作得很完美。
















猜你喜欢

转载自blog.csdn.net/shunzi1046/article/details/76672418