原创:Angular新手容易碰到的坑,随时更新,欢迎订阅

在Angular群里回答新手问题一段时间了,有一些Angular方面的坑留在这里备查,但愿能对各位有所帮助。这个文章未来会随时更新,不会单独开新章,欢迎各位订阅。html

Q1. <div ng-include="views/user/show.html"></div> 错在哪里?jquery

A1. 若是你这么写过,会发现这个位置啥也没有加载出来,那么,错在哪里呢?错在ng-include须要的是一个变量,若是你在$scope中有这样一个变量 $scope.userShowTemplateUrl = "views/users/show.html",而且把上面这句变为<div ng-include="userShowTemplateUrl"></div>就能正常工做了。或者这样写也行:<div ng-include=" 'views/user/show.html' "></div>ajax

缘由何在?chrome

由于在ng-include中,是把它的参数当作变量来解释的,它会经过$eval对传入的值进行计算,而后做为模板地址去加载。app

不过,更好的方法是把这些界面片断(partical)写成指令,那样你就不用在多处重复写路径了,更重要的是,未来你能够直接在这里扩展它的交互逻辑,从界面原型平滑的演化到线上系统。ide

Q2. 个人指令怎么无效?函数

A2. 若是你排除了代码错误等问题,那么最可能的缘由是restrict。restrict参数是用来规定你能够经过哪一种方式来使用指令,而这个问题之因此容易成为坑,是由于restrict的默认值是A,也就是说,默认状况下,指令只能经过属性的形式使用,好比我写了一个指令叫作appHeader,那么默认状况下我只能用这样的形式使用它:<div app-header></div>,而<app-header></app-header>的形式则是无效的。spa

因此,若是你用返回函数的形式使用指令,那么你就只能使用属性的方式调用它,好比:rest

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

若是要使用元素的方式使用指令,那么你就要这样写:code

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。

典型代码以下:

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变量。

相关文章
相关标签/搜索