Angular新手容易碰到的坑

在Angular羣裏回答新手問題一段時間了,有一些Angular方面的坑留在這裏備查,但願能對各位有所幫助。這個文章未來會隨時更新,不會單獨開新章,歡迎各位訂閱。javascript

Q1.<div ng-include="views/user/show.html"></div> 錯在哪裏?

若是你這麼寫過,會發現這個位置啥也沒有加載出來,那麼,錯在哪裏呢?錯在ng-include須要的是一個變量,若是你在$scope中有這樣一個變量 $scope.userShowTemplateUrl = "views/users/show.html",而且把上面這句變爲<div ng-include="userShowTemplateUrl"></div>就能正常工做了。或者這樣寫也行:<div ng-include=" 'views/user/show.html' "></div>php

緣由何在?html

由於在ng-include中,是把它的參數當作變量來解釋的,它會經過$eval對傳入的值進行計算,而後做爲模板地址去加載。java

不過,更好的方法是把這些界面片斷(partical)寫成指令,那樣你就不用在多處重複寫路徑了,更重要的是,未來你能夠直接在這裏擴展它的交互邏輯,從界面原型平滑的演化到線上系統。jquery

Q2. 個人指令怎麼無效?

A2. 若是你排除了代碼錯誤等問題,那麼最可能的緣由是restrict。restrict參數是用來規定你能夠經過哪一種方式來使用指令,而這個問題之因此容易 成爲坑,是由於restrict的默認值是A,也就是說,默認狀況下,指令只能經過屬性的形式使用,好比我寫了一個指令叫作appHeader,那麼默認 狀況下我只能用這樣的形式使用它:<div app-header></div>,而<app-header></app-header>的形式則是無效的。ajax

因此,若是你用返回函數的形式使用指令,那麼你就只能使用屬性的方式調用它,好比:chrome

yourModule.directive('appHeader', function() { return function(scope, element, attrs) { element.text('hello'); } }); 

若是要使用元素的方式使用指令,那麼你就要這樣寫:ruby

yourModule.directive('appHeader', function() { return { restrict: 'E', // 或'EA'等均可以,幾種形式能夠任意組合 link: function(scope, element, attrs) { element.text('hello'); } } }); 

Q3. 修改了變量怎麼界面沒反應?

A3. 首先你固然要檢查有沒有錯誤以及是否確實是scope變量,若是這些都沒問題,那麼多半兒是$apply致使的。對於大多數操做,$apply都會自動執 行,因此你不用擔憂,可是若是你使用了angular以外的功能,好比直接調用了setTimeout函數、掛接了jquery的事件、使用了 jquery的ajax操做等等,那麼系統就沒有機會幫你調用$apply,界面也就沒有機會刷新了,可是你若是以後又作了其餘會致使$apply的操 做,你會發現之前「欠下」的那次界面刷新被正常執行了了 …… 遲到的刷新仍然是bug。markdown

典型代碼以下:app

setTimeout(function() { $scope.time = new Date() }, 1000); 

這種狀況下你在頁面中綁定的time變量將不會被自動刷新,不管是經過{{}}表達式,仍是經過ng-*屬性或者其餘任何形式。怎麼改呢?這樣:

setTimeout(function() { $scope.$apply(function() { $scope.time = new Date(); }); }, 1000); 

不過,這不是最好的形式,最好的形式是什麼呢?固然是使用angular內置的$timeout服務,它就是幹這個的:

$timeout(function() { $scope.time = new Date(); }); 

沒有$apply,卻正常工做,沒bug,並且漂亮多了吧?不過這裏別忘了你得把$timeout服務進行依賴注入,否則它是undefined。

Q4. ng-click 寫成 ng-class 致使的界面中止響應

A4. 這是我本身犯過的一個低級錯誤,屬於深度依賴ide致使的問題。ide的自動代碼提示功能,ng-cl的第一個候選項是ng-class,若是偷懶少打了 一個字,那麼原本想寫ng-click的代碼就會寫成ng-class,結果就是,無休止的從新計算ng-class中的表達式,其中的緣由還沒來得及看 源碼研究。

若是遇到界面中止響應的問題,並且你也一樣深度依賴ide,那麼,從這個角度查查看吧。

Q5. 我知道你不拜金,但別忘了$

A5. 在angular中有一個通用的約定:angular的內部服務、方法、屬性一般都會以$開頭,而相應的,它也要求你本身的命名不要用$開頭。比較容易忘 記用$開頭的主要是一些方法,特別是$apply, $watch, $on, $broardcast, $emit這些,而這些若是你寫錯了,在chrome中你將獲得一個莫名其妙的提示 TypeError: undefined is not a function! 可惡的是,連函數名字都沒有!因此,雖然我知道你不拜金,可是千萬不要忘了寫$!

Q6. 注意做用域的原型繼承問題!

A6. 在Angular中,做用域是經過原型鏈進行繼承的。而這種繼承有一個問題,那就是在子類中對變量進行賦值時,不會去修改父級的。

假設scopeA繼承自scopeB,而在scopeB中定義了一個變量value: 1,這時候,讀取scopeA.value能夠正確取到值,可是若是賦值,就有問題了 scopeA.value = 2,這時候,scopeB.value的值是多少呢?你可能覺得是2,但它是1!緣由就在於原型繼承時對變量的賦值不會修改原型中的值,而是直接在當前scope中建立一個同名的屬性。

這個現象致使了一個容易讓新手困惑的問題:

下面的代碼工做正常:

<label><input type="radio" ng-model="color" value="red"> Red </label><br/> <label><input type="radio" ng-model="color" value="green"> Green</label><br/> <label><input type="radio" ng-model="color" value="blue"> Blue </label><br/> {{color}} 

而下面的代碼工做不正常,color值將不會隨着選擇而變化:

<div ng-repeat="value in ['red', 'green', 'blue']"> <label><input type="radio" ng-model="color" ng-value="value"> {{value}} </label> </div> {{color}} 

它的緣由就在於color值定義在當前scope中,而ng-repeat建立了一個子scope,它使用原型繼承的方式從父級繼承下來。對color值的修改,會去修改子級的變量,而父級的同名變量不會被修改。

要想讓它正常工做,就改爲這樣:

<div ng-repeat="value in ['red', 'green', 'blue']"> <label><input type="radio" ng-model="vm.color" ng-value="value"> {{value}} </label> </div> {{vm.color}} 

這裏,把color定義成了一個vm對象的屬性,這時候,由於只須要對vm的成員進行賦值,而不存在對vm進行賦值的情 況,因此賦值會正確的做用於父級scope上。這裏的vm只是$scope上的一個對象,叫別的名字也能夠,只是由於它的實際做用是ViewModel, 因此我習慣於把它命名爲vm。

在Angular 1.2之後的版本中引入了controllerAs語法,能夠一勞永逸的解決這個問題。具體的用法請參見 http://www.cnblogs.com/whitewolf/p/3493362.html

若是使用1.2如下的版本,能夠在controller的第一句加上這樣的語法來模擬:

var vm = $scope.vm = {};
全部的$scope變量都改成賦值給vm變量就能夠了,view中也要相應的引用vm變量。

Q7. angular.module的兩種寫法:含義大不一樣

angular.module('name', [])angular.module('name') 雖然看起來很類似,可是!它們的含義倒是大相徑庭的!

angular.module('name', [])是建立一個新的module,[]表示它沒有依賴任何其餘模塊,若是已經有了一個同名模塊,則會覆蓋現有的。

angular.module('name')是查找一個現有module,若是這個module不存在,則返回空值。

若是把帶方括號的形式(建立)誤用爲不帶方括號的形式(引用),那麼在它的返回值上調用controller等函數會出現空指針錯誤。

而若是把引用形式誤用爲建立形式,則會致使難以理解的「對象不存在」錯誤,可是你卻明明定義過那個service或者controller等對象!這種問題就是由於後面的模塊定義覆蓋了之前的模塊定義,你定義過的那些對象都被隨着之前的module而丟掉了!

Q8. 第三方指令不起做用

最可能的緣由是你沒有加入模塊依賴。第三方指令一般會定義在本身的模塊中,因此這個模塊必須被你的app模塊所依賴,其中包含的指令才能在view中使用。好比你要使用ui-select2指令,就必須在本身的模塊定義中加入這個依賴:

angular.module('app', [ 'ngCookies', 'ngResource', 'ngSanitize', 'ui.select2' ])..... 

若是仍然沒有解決問題,請看看控制檯中有沒有錯誤信息,以及是否存在Q2所提的狀況。

相關文章
相關標籤/搜索