iT邦幫忙

DAY 6
1

我在前端 ng 時系列 第 6

ng-if & ng-show

我們很常遇到的需求是當某些條件成立時,畫面上特定地方要把它藏起來,不能讓使用者看到。
這時候就是 ng-If 跟 ng-show 出場的時候。

ng-show: 條件不成立的時候隱藏 element。即套用 CSS 樣式: display: none !important;
ng-hide: ng-show 的相反,條件成立,判斷式為 true 的時候套用 display:none
ng-If: 依照判斷式,動態產生或移除 DOM tree 裡的 element

ng-show 行為跟 ng-hide 除了判斷一個是 true 顯示,一個是 true 隱藏,行為都是在修改 element 的 display style。
所以後來 ng-hide 我都用 ng-show=“ !condition “ 代替,使用相同的名稱用法方便管理。


心得一: 小心 pseudo-classes

ng-show 雖然看不到,但仍存在 DOM tree 裡面,
所以依然會被 CSS 的 :nth-child 或 :first-child 等 pseudo-classes 選到。

範例:

在這個 list 中,我使用 ng-show 讓只有偶數列數中顯示背景色紅色。

結果:

http://jsfiddle.net/o6g93430/1/

耶?怎麼一排紅色都沒有?
檢查一看才發現,CSS Pseudo-class 選到的都是被隱藏的 element。

這時候改用 ng-if 就可以輕鬆解決這個問題。

http://jsfiddle.net/o6g93430/2/

因為 ng-if 是當條件不成立的時候, 不會在 DOM tree 產生 element。
所以 tr element 並沒有 render 在頁面上,CSS Pseudo-class 也就不會選到。

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

心得二: ng-If 的注意事項

先來一段官網的 documentation:

Note that when an element is removed using ngIf its scope is destroyed and a new scope is created when the element is restored.

element 在 ng-If=true 的時候,會產生一個新的 isolate scope。
所以當綁定的 model 是在 ng-if 的 scope,小心在 ng-if 切換 true/false 的過程,model 值會不見。
範例: http://jsfiddle.net/hokvj87z/1/

那假如把 ng-if 裡面的 model 改綁在 controller 的 scope 裡面會不會解決上面的問題呢?
答案是假如 model 是原生類型(primitive type)就不會。
範例:http://jsfiddle.net/hokvj87z/2/

再來段官網 documentation:

An important implication of this is if ngModel is used within ngIf to bind to a javascript primitive defined in the parent scope. In this case any modifications made to the variable within the child scope will override (hide) the value in the parent scope.

在 children (ng-If’s scope)產生的原生類型是不會影響到 parent (myCtrl’s scope) 。
所以說當我們在 ngIf scope 中改原生類型 model 其實不會改到 parent scope 的原生類型 model,而改到 ngIf 本身 scope 裡的 model。
重新切換 ngIf true/false 會因為 scope 被重新產生而讓 model 重新被建立。

上面問題有兩種解決方式。

  1. 改用 object 綁定 model,原理牽扯到很複雜的 scope 觀念
    直接看範例:http://jsfiddle.net/hokvj87z/3/

這招非常好用,有機會未來再深入說明...
(當在會產生 isolate scope 的 directive link function 中修改 scope.model 的時候,
遇到無法跟 parent 同步修改的問題時。大概十之八九都是原生類別的問題。)

2. 使用 controller as syntax 把 model 綁在 controller 上面
http://jsfiddle.net/hokvj87z/4/

理由同上,controller 本身就是一個 object,
所以 model 是綁在 object 上在 pass 進 ng-if 的時候就不會有問題。

綁在 controller 上跟綁在 controller 的 scope 狀況不一樣噢。
一個是綁在 controller 本身上面(沒問題的),一個是綁在跟 controller 同層的 scope 上面。 (有問題的)

-----------

心得三: ng-if + ng-repeat 怪怪的?

有時候使用 ng-if +ng-repeat 會出現問題(不管是出現錯誤訊息,或是 ng-repeat 出現的列表順序跟原本的不一樣)
大部份原因是 ng-repeat 跟 ng-if 兩者會產生出 isolated scope,導致 multiple transclusion error 。
假如有遇到,可改用 ng-show 或是 list $filter 去避掉問題。

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

心得四: 要使用 ng-if 還是 ng-show?

現在我的習慣幾乎都是用 ng-if,不在 DOM tree 產生 element ,效能比較好。
除非 DOM 的 Show/Hide 可能會被頻繁的切換,這樣我會改用 ng-show。

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

心得五: 使用 ng-if 時,要注意綁事件的方式。

遇到 element 需要被非 AngularJS 方式綁住的時候。(例如 jQuery)
假如 DOM 因為 ng-if 的關係,在 jQuery 綁事件前尚未 render 出來。導致因找不到 DOM element 而不會綁定事件。
就算 element 後來因為 ng-if=true 的關係 render 出來了,事件也不會自動幫你綁上去。
因為 JavaScript 已經過了綁事件的時機,除非你自己在 DOM element 建立後馬上把事件綁上去。
http://plnkr.co/edit/55YdAEgWKccJdDDiptA4?p=preview

這個問題改用 ng-show 問題就解決了。
http://plnkr.co/edit/5SJyXjq3XUCD4pySzCrz?p=preview

或最根本的,繼續用 ng-if 搭配用 ng-click , ng-mouseover 等其他 AngularJS 的方式來綁定事件
http://plnkr.co/edit/jqcaBbc9Xt4JknW8h7HD?p=preview

這集寫好久喔 >"< 如果有任何問題,歡迎留言討論喔!


上一篇
相見恨晚 - Lo-Dash
下一篇
AngularJS Forms 的經驗談
系列文
我在前端 ng 時30

尚未有邦友留言

立即登入留言