學習如何編寫顯示數據並在數據綁定的幫助下使用用戶事件的模板。
Angular應用程序管理用戶看到和能夠作的事情,經過組件類實例(組件)和麪向用戶的模板的交互來實現這一點。
您能夠熟悉模型 - 視圖 - 控制器(MVC)或模型 - 視圖 - 視圖模型(MVVM)的組件/模板。 在Angular中,組件扮演控制器/視圖模型的一部分,模板表示視圖。html
本指南涵蓋了Angular模板語法的基本元素,以及構建視圖所需的元素:java
現成示例(查看源代碼)演示了本指南中描述的全部語法和代碼片斷。git
HTML是Angular模板的語言。 幾乎全部的HTML語法都是有效的模板語法。 <script>元素是一個值得注意的例外。 這是被禁止的,消除腳本注入攻擊的風險。 在實踐中,<script>被忽略,並在瀏覽器控制檯中出現警告。 有關詳情,請參閱安全性頁面。github
一些合法的HTML在模板中沒有多大意義。 <html>,<body>和<base>元素沒有用處。 剩下一切都是一致的。web
您可使用組件和指令出現的新元素和屬性來擴展模板的HTML詞彙表。 在下面的章節中,您將學習如何經過數據綁定來動態獲取和設置DOM(文檔對象模型)值。express
從數據綁定插值的第一種形式開始,看看有多少更豐富的模板HTML可使用。請回到頂部。api
在Angular的早期教程中,你遇到了插值的雙曲括號{{and}}。瀏覽器
<p>My current hero is {{currentHero.name}}</p>
您可使用插值將計算的字符串組織到HTML元素標記和屬性賦值之間的文本中。緩存
<h3> {{title}} <img src="{{heroImageUrl}}" style="height:30px"> </h3>
大括號裏的文本一般是組件屬性的名稱。 Angular用相應的屬性值替換該名稱。 在上面的例子中,Angular評估了title和heroImageUrl屬性,並「填充空白」,首先直接顯示一個應用標題,而後是一個英雄圖像。安全
更多的,大括號之間的文本是一個模板表達式,Angular首先評估並轉換爲一個字符串, 經過添加這兩個數字來進行如下內插:
<!-- "The sum of 1 + 1 is 2" --> <p>The sum of 1 + 1 is {{1 + 1}}</p>
該表達式能夠調用主機的方法,例如getVal(),以下所示:
<!-- "The sum of 1 + 1 is not 4" --> <p>The sum of 1 + 1 is not {{1 + 1 + getVal()}}</p>
Angular用雙曲花括號評估全部表達式,將表達式結果轉換爲字符串,並將它們與相鄰的文字串相連接。最後,它將這個複合插值結果賦值給一個元素或指令屬性
您彷佛在元素標記之間插入結果並將其分配給屬性。這麼想很方便,你會由於這個錯誤而受苦。雖然這不徹底正確。插值是收斂到屬性綁定中的一種特殊語法,以下所述。
但首先,讓咱們仔細看看模板表達式和語句。
模板表達式產生一個值。 Angular執行表達式並將其分配給綁定目標的屬性; 目標多是HTML元素,組件或指令。
{{1 + 1}}中的內插大括號包圍模板表達式1 + 1.在下面的屬性綁定部分中,在[property] =「expression」中,模板表達式顯示在符號右側的引號中。
你用相似Dart的語言編寫這些模板表達式。 許多Dart表達式是合法的,但不是所有。
帶有或促進反作用的Dart表達式是被禁止的,包括:
與Dart語法的其餘顯着差別包括:
不支持Dart字符串插值; 例如,而不是「'The title is $title'」,你必須寫''The title is ' + title'「
不支持按位運算符| 和&
新的模板表達式運算符,如|
表達式上下文一般是組件實例。 在如下片斷中,雙花括號內的標題和引號中的isUnchanged引用了AppComponent的屬性。
{{title}} <span [hidden]="isUnchanged">changed</span>
一個表達式也能夠用來引用模板上下文的屬性,包括模板輸入變量(let hero)或模板引用變量(#heroInput)。
<div *ngFor="let hero of heroes">{{hero.name}}</div> <input #heroInput> {{heroInput.value}}
表達式中術語的上下文是模板變量和組件成員的混合。 若是引用這些名稱空間的名稱,則模板變量名稱優先,後面是指令的上下文,最後是組件的成員名稱。
前面的例子顯示了這樣一個名字衝突。 該組件具備hero屬性,而* ngFor定義了英雄模板變量。 {{hero.name}}中的英雄是指變量輸入變量,而不是組件的屬性。
模板表達式不能引用靜態屬性,也不能引用頂層變量或函數,如來自dart:html的window 或document 。他們不能直接調用從dart:math導入的print或函數。 它們僅限於引用表達式上下文的成員。
模板表達式能夠構建或破壞應用程序。 請遵循如下準則:
這些指導方針的例外狀況應該是在你理解的狀況下。
模板表達式不該該更改目標屬性的值之外的任何應用程序狀態。
這個規則對Angular的「單向數據流」策略是必不可少的。您沒必要擔憂讀取組件值可能會改變一些其餘的顯示值。這個視圖在整個渲染過程當中應該是穩定的。
Angular在每一個更改檢測週期後執行模板表達式。 更改檢測週期由許多異步活動觸發,如承諾的分辨率,http結果,計時器事件,按鍵和鼠標移動。
表達式應該快速完成,不然用戶可能會遇到卡幀,尤爲是在較慢的設備上。 當他們的計算成本很高時,考慮緩存值。
雖然能夠編寫至關複雜的模板表達式,可是應該避免使用它們。
屬性名稱或方法調用應該是標準。 偶爾的布爾否認(!)能夠。
另外, 將應用和業務邏輯放到到組件自己,在那裏它將更容易開發和測試。
冪等表達式是理想的,由於它沒有反作用,而且改善了Angular的變化檢測性能。
對Angular來講,一個冪等表達式老是返回徹底相同的東西,直到它的一個依賴值發生變化。
在事件循環的一個回合期間,依賴值不該該改變。若是一個冪等表達式返回一個字符串或一個數字,當它在一行中調用兩次時會返回相同的字符串或數字。若是表達式返回一個對象(包括一個List),它將在連續調用兩次時返回相同的對象引用。
模板語句響應綁定目標(例如元素,組件或指令)引起的事件。 您會在事件綁定部分看到模板語句,並在(event)=「statement」中出如今=符號右側的引號中。
<button (click)="deleteHero()">Delete hero</button>
模板語句有一方面的做用。 它是一個事件的所有。 就是如何從用戶操做更新應用程序狀態。
響應事件是Angular的「單向數據流」的另外一面。在事件循環的這個週期中,您能夠自由地在任何地方進行全部更改。
像模板表達式同樣,模板語句使用了一種看起來像Dart的語言。 模板語句解析器與模板表達式解析器不一樣,特別支持基本的賦值(=)和連接表達式(with;)
可是,某些Dart語法是不容許的:
與表達式同樣,語句只能引用語句上下文中的內容,例如組件實例的事件處理方法。
語句上下文一般是組件實例。 (click)=「deleteHero()」中的deleteHero是數據綁定組件的一種方法。
<button (click)="deleteHero()">Delete hero</button>
語句上下文也能夠引用模板本身的上下文的屬性。 在如下示例中,將模板$ event對象,模板輸入變量(let hero)和模板引用變量(#heroForm)傳遞給組件的事件處理方法。
<button (click)="onSave($event)">Save</button> <button *ngFor="let hero of heroes" (click)="deleteHero(hero)">{{hero.name}}</button> <form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>
模板上下文字段優先於組件上下文字段。 在上面的deleteHero(hero)中,hero是模板輸入變量,而不是組件的hero屬性。
模板語句不能引用類的靜態屬性,也不能引用頂層變量或函數,如來自dart:html的window或document 。 它們不能直接調用從dart:math導入的print或函數。
與表達式同樣,避免編寫複雜的模板語句。 方法調用或簡單的屬性分配應該是標準。
如今您已經感受到了模板表達式和語句,您已經準備好了解超越插值的各類數據綁定語法。
數據綁定是一種協調用戶看到應用程序數據值的機制。 雖然您能夠將值推送到HTML中,並從HTML中提取值,可是若是將這些瑣事轉換爲綁定框架,則應用程序更易於編寫,讀取和維護。 您只需聲明綁定源和目標HTML元素之間的綁定,而後讓框架完成工做。
Angular提供了多種數據綁定。 本指南涵蓋了大部分的Angular數據綁定及其語法的高級使用。
綁定類型能夠按照數據流的方向分爲三類:source-to-view,view-to-source,以及雙向順序:view-to-source-to-view:
數據方向 | 語法 | 類型 |
---|---|---|
單向 從數據源到目標視圖 |
{{expression}} [target]="expression" bind-target="expression"
|
插值 組件屬性 元素屬性 元素類 元素樣式 |
單向 從目標視圖到數據源 |
(target)="statement" on-target="statement"
|
事件 |
雙向 | [(target)]="expression" bindon-target="expression"
|
雙向 |
除插值之外的綁定類型在等號左邊或者用標點符號([],())包圍,或者帶前綴(bind-,on-,bindon-)都有一個目標名稱。
目標名稱是一個屬性的名稱。 它可能看起來像一個元素屬性的名稱,但它不是。 爲了體會差別性,您必須開發一種思考HTML模板的新方法。
藉助數據綁定的全部功能以及使用自定義標記擴展HTML詞彙表的能力,將HTML模板視爲HTML Plus是頗有誘惑力的
它確實是HTML Plus。 可是它也與你習慣的HTML有很大的不一樣。 它須要一個新的心智模式。
在HTML開發的正常過程當中,您可使用HTML元素建立一個可視結構,並經過使用字符串常量設置元素屬性來修改這些元素。
<div class="special">Mental Model</div> <img src="assets/images/hero.png"> <button disabled>Save</button>
您仍然在Angular模板中以這種方式建立結構並初始化屬性值。
而後,您將學習如何使用封裝了HTML的組件建立新元素,並將它們放入模板中,就好像它們是原生HTML元素同樣。
<!-- Normal HTML --> <div class="special">Mental Model</div> <!-- Wow! A new element! --> <hero-detail></hero-detail>
這是HTML Plus。
而後你學習數據綁定。 你遇到的第一個綁定多是這樣的:
<!-- Bind button disabled state to `isUnchanged` property --> <button [disabled]="isUnchanged">Save</button>
你的直覺可能代表你綁定了按鈕的disabled屬性,並將其值設置爲組件的isUnchanged屬性的當前值。 那個直覺是不正確的!
平常的HTML心智模式是誤導性的。 一旦你開始數據綁定,你再也不使用HTML Attributes 。 你不是設置屬性(Attributes) ; 你應該設置DOM元素,組件和指令的屬性(Properties)。
HTML屬性(Attributes)與DOM屬性(Properties)
HTML屬性和DOM屬性的區別對於理解Angular綁定是如何工做是相當重要的。
Attributes 由HTML定義。Properties 由DOM(文檔對象模型)定義。
- 一些HTML屬性(Attributes)映射到屬性(Properties)1:1, id是一個例子。
- 一些HTML屬性(Attributes)沒有相應的屬性(Properties)。 colspan就是一個例子。
- 一些DOM屬性(Properties)沒有相應的屬性(Attributes)。 textContent就是一個例子。
- 許多HTML屬性(Attributes)彷佛映射到屬性(Properties)...但不是以你想象的方式!
最後一個類別含義模糊的,除非你知道這個通常規則:
屬性(Attributes)初始化DOM屬性(Properties),而後完工。 屬性(Properties)值能夠會改變; 屬性(Attributes)值不能。
例如,當瀏覽器呈現<input type =「text」 value =「Bob」>時,它會建立一個對應的DOM節點,其值屬性(Properties)已初始化爲「Bob」。
當用戶在輸入框中輸入「Sally」時,DOM元素值屬性變爲「Sally」。 可是,HTML value屬性保持不變,當訪問輸入元素的該屬性:input.getAttribute('value')返回「Bob」。
HTML屬性(Attributes) value指定初始值; DOM value屬性(Properties)是當前值。
disabled 屬性(Attributes)是另外一個特殊的例子。 按鈕的disabled 屬性(Properties)默認爲false,所以按鈕已啓用。 當您添加disabled屬性(Attributes)時,它的存在會將按鈕的disabled屬性(Properties)初始化爲true,所以該按鈕被禁用。
添加和刪除disabled屬性(Attributes)將禁用和啓用該按鈕。
該屬性(Attributes)的值是可有可無的,這就是爲何您不能經過編寫<button disabled =「false」> Still Disabled </ button>來啓用按鈕的緣由。設置按鈕的disabled屬性(Properties)(例如,使用Angular綁定)禁用或啓用按鈕。屬性(Properties)的值很重要。
HTML屬性(Attributes)和DOM屬性(Properties)是不同的,即便它們具備相同的名稱。
這個事實值得重複:模板綁定使用屬性(properties)和事件(events)發揮做用,而不是屬性(attributes)。
一個沒有屬性的世界
在Angular的世界中,屬性(attributes)的惟一做用是初始化元素和指令狀態。 當你寫數據綁定時,你只處理目標對象的屬性(properties)和事件(events)。 HTML屬性(attributes)不起做用。
記住這個模型,繼續閱讀以瞭解綁定目標。
數據綁定的目標是DOM中的東西。根據綁定類型,目標能夠是(element | component |directive)屬性,(element | component | directive)事件或(不多)屬性(attributes)名稱。 下表總結了這些狀況:
Type | Target | Example |
---|---|---|
Property | Element property Component property Directive property |
<img [src]="heroImageUrl"> <hero-detail [hero]="currentHero"></hero-detail> <div [ngClass]="{special: isSpecial}"></div>
|
Event | Element event Component event Directive event |
<button (click)="onSave()">Save</button> <hero-detail (deleteRequest)="deleteHero()"></hero-detail> <div (myClick)="clicked=$event" clickable>click me</div>
|
Two-way | Event and property | <input [(ngModel)]="name">
|
Attribute | Attribute (例外) | <button [attr.aria-label]="help">help</button>
|
Class | class property | <div [class.special]="isSpecial">Special</div>
|
Style | style property | <button [style.color]="isSpecial ? 'red' : 'green'">
|
您如今已經準備好詳細查看綁定類型。
編寫一個模板屬性綁定來設置一個視圖元素的屬性。 該綁定將該屬性設置爲模板表達式的值。
最多見的屬性綁定將元素屬性設置爲組件屬性值。一個示例是將圖像元素的src屬性綁定到組件的heroImageUrl屬性:
<img [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>
人們一般將屬性綁定描述爲單向數據綁定,由於它從一個組件的數據屬性向一個目標元素屬性傳遞一個值。
您不能使用屬性綁定將值從目標元素中拉出。 您不能綁定到目標元素的屬性來讀取它。 你只能設置它。
一樣,您不能在目標元素上使用屬性綁定來調用方法。
若是元素引起事件,則可使用事件綁定來監聽它們。
若是您必須讀取目標元素屬性或調用其中一個方法, 你須要一個不一樣的技術。 查看ViewChild和ContentChild的API參考。
方括號之間的元素屬性標識目標屬性。 如下代碼中的目標屬性是圖像元素的src屬性。
<img [src]="heroImageUrl">
有些人更喜歡綁定前綴bind-替代,稱爲規範形式:
<img bind-src="heroImageUrl">
目標名稱始終是屬性(property)的名稱,即便它看起來是別的名稱。 你可能會看到src,並認爲它是一個屬性(attribute)的名稱。 不是; 這是一個圖像元素屬性(property)的名稱。
元素屬性(property)多是更常見的目標,但Angular首先查看名稱是不是已知指令的屬性(property),以下例所示:
<div [ngClass]="classes">[ngClass] binding to the classes property</div>
從技術上講,Angular將名稱與指令輸入或用@Input()裝飾的屬性相匹配。 這樣的輸入映射到指令本身的屬性。
若是名稱未能匹配已知指令或元素(property)的屬性,則Angular會報告「未知指令」錯誤。
如前所述,模板表達式的評估必須沒有可見的反作用。表達式語言自己是爲了保證您的安全。您不能爲屬性綁定表達式中的任何東西賦值,也不能使用增量和減量運算符。
固然,該表達式可能會調用具備反作用的屬性或方法。 Angular沒法知道或阻止你。
該表達式能夠調用相似getFoo()的東西。 只要你知道getFoo()是作什麼的。若是getFoo()改變了某些東西,並且碰巧綁定了某些東西,你將冒着必定的風險。Angular可能會或可能不會顯示更改的值。Angular可能會檢測到更改併發出警告錯誤。一般來講,保留數據屬性和方法返回值就夠了。
模板表達式應經過目標屬性計算預期值的類型:
HeroDetail組件的hero屬性須要一個Hero對象,這正是你在屬性綁定中發送的內容:
<hero-detail [hero]="currentHero"></hero-detail>
檢查模式異常
在檢查模式下,若是模板表達結果類型和目標屬性類型不是賦值兼容的,則會拋出一個類型異常。 有關檢查模式的信息,請參閱Dart語言指南中的重要概念。
Dart 2.0注意:檢查模式不會出如今飛鏢2.0。 有關更多信息,請參閱Dart 2.0更新。
記住括號
括號告訴Angular評估模板表達式。 若是省略方括號,Angular會將該字符串視爲常量,並使用該字符串初始化目標屬性。 它不評估字符串!
不要犯如下錯誤:
<!-- ERROR: A value of type 'String' can't be assigned to a variable of type 'Hero'. <hero-detail hero="currentHero"></hero-detail> -->
檢查模式類型異常例子
在檢查模式下,上面的代碼將致使一個類型異常:String不是Hero的子類型。
知足如下全部條件時,省略括號:
一次性字符串初始化在標準HTML中是常規的,而且它對於指令和組件屬性也一樣適用。 如下示例將HeroDetailComponent的prefix屬性初始化爲固定字符串,而不是模板表達式。 Angular設置它並再也不管它。
<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>
另外一方面,[hero]綁定仍然保留對組件的currentHero屬性的有效綁定。
你常常有插值和屬性綁定的選擇。 如下綁定作一樣的事情:
<p><img src="{{heroImageUrl}}"> is the <i>interpolated</i> image.</p> <p><img [src]="heroImageUrl"> is the <i>property bound</i> image.</p> <p><span>"{{title}}" is the <i>interpolated</i> title.</span></p> <p>"<span [innerHTML]="title"></span>" is the <i>property bound</i> title.</p>
在許多狀況下插值是屬性綁定較爲方便的替代品。
將數據值呈現爲字符串時,沒有技術上的理由去選擇另外一種形式,但插值更可讀。咱們建議創建編碼風格規則,選擇符合規則的形式,對於手頭的任務來講是最天然的
將元素屬性設置爲非字符串數據值時,必須使用屬性綁定。
想象下面的惡意內容。
String evilTitle = 'Template <script>alert("evil never sleeps")</script>Syntax';
幸運的是,Angular數據綁定對危險的HTML進行了警報。 它在顯示它們以前清理這些值。 它不容許帶腳本標記的HTML泄露到瀏覽器中,既不能使用插值也不能使用屬性綁定。
<!-- Angular generates warnings for these two lines as it sanitizes them WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss). --> <p><span>"{{evilTitle}}" is the <i>interpolated</i> evil title.</span></p> <p>"<span [innerHTML]="evilTitle"></span>" is the <i>property bound</i> evil title.</p>
插值處理腳本標記與屬性綁定不一樣,但兩種方法均無害地呈現內容。
模板語法爲不太適合屬性(property )綁定的場景提供了專門的單向綁定。
您能夠直接使用屬性綁定來設置屬性的值。
這是綁定設置目標屬性(property)的惟一例外規則。 這是建立和設置屬性(attribute)的惟一一種綁定。
本指南反覆強調,使用屬性(property)綁定設置元素屬性(property)始終優先於使用字符串設置屬性(attribute)。 Angular爲何提供屬性(attribute)綁定?
當沒有要綁定的元素屬性時,必須使用屬性綁定。
考慮ARIA,SVG和table span屬性。 他們是純粹的屬性。 它們不對應元素屬性,也不設置元素屬性。 沒有屬性目標綁定。
在寫像這樣的東西時,這個事實變得很是明顯:
<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
正如消息所述,<td>元素沒有colspan屬性。 它具備「colspan」屬性(attribute),可是插值和屬性(attribute)綁定只能設置屬性(properties),而不能設置屬性(attribute)。
您須要屬性(attribute)綁定來建立和綁定到這些屬性(attribute)。
屬性(attribute)綁定語法相似於屬性(properties)綁定。之前綴attr開頭,後跟一個點(.)和屬性名稱代替括號之間的元素屬性。而後使用解析爲字符串的表達式來設置屬性值。
將[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>
如下是表格的呈現方式:
屬性(attribute)綁定的主要用例之一是設置ARIA屬性,以下例所示:
<!-- create and set an aria attribute for assistive technology --> <button [attr.aria-label]="actionName">{{actionName}} with Aria</button>