腊月的季节

angularjs之内置指令

ng属性指令

  • ng-href
  • ng-src
  • ng-disabled
  • ng-checked
  • ng-readonly
  • ng-selected
  • ng-class
  • ng-style

布尔属性

布尔属性代表一个true或false值。当这个属性出现时,这个属性的值就是true,如果未出现,这个属性就是false。
当在angularjs中使用动态数据绑定时,不能简单地将这个属性值设置为true或false,因为根据标准定义只有当这个属性不出现时,它的值才为false。因此angularjs提供了一组带有ng-前缀版本的布尔属性,通过运算表达式的值来决定在目标元素上是插入还是移除对应的属性。

  • ng-disabled
    使用ng-disabled可以把disabled属性绑定到一下表单输入字段上:
    1
    2
    3
    4
    <input>(text,checkbox,radio,number,url,email,submit)
    <textarea>
    <select>
    <button>

当写普通的HTML输入字段时,如果在元素标签上出现了disabled属性就会禁用这个输入字段。通过ng-disabled可以对是否出现属性进行绑定。例如,在下面的例子中按你会一直被禁用,知道用户在文本字段中输入内容:

1
2
<input type="text" ng-model="someProperty" placeholder="TypetoEnable">
<button ng-model="button" ng-disabled="!someProperty">AButton</button>

在下面的例子,文本字段会被禁用五秒,知道在\$timeout中将isDisabled属性设置为true:

1
2
3
4
5
6
7
8
<textarea ng-disabled="isDisabled">Wait5seconds</textarea>
angular.module('myApp',[])
.run(function($rootScope,$timeout){
$rootScope.isDisabled=true;
$timeout(function(){
$rootScope.isDisabled = false;
},5000)
});

  • ng-readonly
    同其他布尔属性一样,HTML定义只会检查readonly属性是否出现,而不是他的实际值。通过ng-readonly,可以将某个返回真或假的表达式同是否出现readonly属性进行绑定在,作用是是否只读:

    1
    2
    <input type="text" ng-model="someProperty"><br/>
    <input type="text" ng-readonly="someProperty" value="some text here"/>
  • ng-checked
    标准的checked属性是一个布尔属性,不需要进行赋值,通过ng-checked将某个表达式同是否出现checked属性进行绑定
    在下面的例子中,我们通过ng-init指令将someProperty的值设置为true。将some Property同ng-checked绑定在一起,angularjs会输出标准的HTML checked属性,这样默认会把复选框勾选:

    1
    2
    <label>someProperty={{someProperty}}</label>
    <input type="checkbox" ng-checked="someProperty" ng-init="someProperty=true" ng-model="someProperty">

下面的例子刚好相反:

1
2
<label>someProperty = {{anotherProperty}}</label>
<input type="checkbox" ng-checked="anotherProperty" ng-init="anotherProperty=false" ng-model="anotherProperty">

注意,为了展示,这里用ng-model把someProperty和anotherProperty的值绑定到了对应的

  • ng-selected
    ng-selected可以对是否出现option标签的selected属性进行绑定:
    1
    2
    3
    4
    5
    6
    <label>Select Two Fish:</label>
    <input type="checkbox" ng-model="isTwoFish"><br/>
    <select>
    <option>One Fish</option>
    <option ng-selected="isTwoFish">Two Fish</option>
    </select>

类布尔属性

ng-href、ng-src等属性虽然不是标准的HTML布尔属性,但是由于行为相似,所以在angularjs源码内都是和布尔属性同等对待的。

  • ng-href
    当使用当前作用域中的属性动态创建URL时,应该用ng-href代替href。
    这里的潜在问题是当用户点击一个由插值动态生成的链接时,如果插值尚未生效,将会跳转到错误的页面。
    这时,如果使用ng-href,angularjs会等到插值生效后再执行点击链接的行为:
    1
    2
    3
    4
    <!-- 当href包含一个{{expression}}时总是使用ng-href -->
    <a ng-href="{{myHref}}">I`m feeling lucky,when i load</a>
    <!-- 用户单击之前,hrefe不会加载-->
    <a href="{{myHref}}">I`m feeling 404</a>

将插值生效的事件延迟两秒,来观察实际的行为:

1
2
3
4
5
6
angular.module('myApp',[])
.run(function($rootScope,$timeout){
$timeout(function(){
$rootScope.myHref="http://www.baidu.com";
},2000);
});

  • ng-src
    angularjs会告诉浏览器在ng-src对应的表达式生效之前不要加载图像:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <h1>wrongway</h1>
    <img src="{{imgSrc}}"/>
    <h1>Rightway</h1>
    <img ng-src="{{imgSrc}}"/>
    angular.module('myApp',[])
    .run(function($rootScope,$timeout){
    $timeout(function(){
    $rootScope.imgSrc='https://www.google.com/images/srpr/logo11w.png';
    },2000);
    });

在指令中使用子作用域

下面将要介绍的指令会以父级作用域为原型生成子作用域。这种继承的机制可以创建一个隔离层,用来将需要协同工作的方法和数据模型对象放置在一起。
ng-app和ng-controller是特殊的指令,因为它们会修改嵌套在它们内部的指令的作用域。
ng-app为angularjs应用创建\$rootScope,ng-controller则会以\$rootScope或另外一个ng-controller的作用域为原型创建新的子作用域。

  • ng-app
    任何具有ng-app属性的DOM元素将被标记为\$rootScope的起始点。
    $rootScope是作用域链的起始点,任何嵌套在ng-app内的指令都会继承它。在JavaScript代码中通过run方法来访问\$rootScope。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <html ng-app="myApp">
    <body>
    {{someProperty}}
    <button ng-click="someAction()"></button>
    </body>
    </html>
    angular.module('myApp',[])
    .run(function($rootScope){
    $rootScope.someProperty = 'hello computer';
    $rootScope.someAction = function(){
    $rootScope.someProperty = 'hello numan';
    };
    });
  • ng-controller
    内置指令ng-controller的作用是为嵌套在其中的指令创建一个子作用域,避免将所有操作和模型都定义在\$rootScope上。用这个指令可以在一个DOM元素上放置控制器。
    ng-controller接受一个参数expression,这个参数是必需的。
    expression参数是一个angularjs表达式。
    子\$scope只是一个JavaScript对象,其中含有从父级\$scope中通过原型继承得到的方法和属性,包括应用的\$rootScope.
    嵌套在ng-controller中的指令有访问新子\$scope的权限,但是要牢记每个指令都应该遵守的和作用域相关的规则。\$scope对象的职责是承载DOM中指令所共享的操作和模型。操作指的是\$scope上标准的JavaScript方法,模型指的是\$scope上保存的包含瞬时状态数据的JavaScript对象。持久化状态的数据应该保存到服务器中,服务的作用是处理模型的持久化。
    控制器应用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <div ng-controller="someController">
    {{someBareValue}}
    <button ng-click="someAction()">Communicate to child</button>
    <div ng-controller="childController">
    {{someBareValue}}
    <button ng-click = "childAction()">Communicate to parent</button>
    </div>
    </div>
    angular.module('myApp',[])
    .controller('SomeController',function($scope){
    //反模式,裸值
    $scope.someBareValue = 'hello computer';
    //设置 $scope 本身的操作,这样没问题
    $scope.someAction = function(){
    //在someBareValue = 'hello numan,from parent';
    };
    .controller('ChildController',function($scope){
    $scope.childAction = function(){
    //在ChildController中设置{{someBareValue}}
    $scope.someBareValue = 'hello numan,from child';
    }
    }
    });

由于原型继承的关系,修改父级对象中的someBareValue会同时修改子对象中的值,但反之则不行。
可以看下这个例子的实际效果,首先点击childButton,然后点击parentButton,这个例子充分说明了子控制器是复制而非引用someBareValue。
JavaScript对象要么是值复制要么是引用复制。字符串、数组和布尔型变量是值复制。数组、对象和函数则是引用复制。
如果将模型对象的某个属性设置为字符串,他会通过引用进行共享,因此在子$scope中修改属性也会修改父\$scope中的这个属性。下面的例子展示了正确的做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div ng-controller="someController">
{{someModel.somevalue}}
<button ng-click="someAction()"> Communicate to child</button>
<div ng-controller="ChildController">
{{someModel.somevalue}}
<button ng-click = "childAction()">Communicate to parent</button>
</div>
</div>
angular.module('myApp',[])
.controller('SomeController',function(){
//最佳实践,永远用一个模式
$scope.someModel={
someValue : 'hello coputer'
}
$scope.someAction = function(){
$scope.someModel.someValue = 'hello human,from parent';
};
})
.controller('ChildController',function($scope){
$scope.childAction = function(){
$scope.someModel.someValue = 'hello human,from child';
}
})

无论点击哪个按钮,值都会进行同步修改。
注意,虽然这个特性是实用ng-controller时最重要的特性之一,但在实用任何会创建子作用域的指令时,如果将指令定义中的scope设置为true,这个特性也会带来负面影响。下面的内置指令都有同样的特性:
ng-include,ng-switch,ng-repeat,ng-view,ng-controller,ng-if.

  • ng-include
    实用ng-include可以加载、编译包含外部HTML片段到当前的应用中。模板的URL被限制在与应用文档相同的域和协议下,可以通过白名单或包装成被信任的值来突破限制。更进一步,需要考虑跨域资源共享和同源规则来确保模板可以在任何浏览器中正常加载。例如,所有浏览器都不能进行跨域的请求,部分浏览器也不能访问file://协议的资源。
    在同一个元素上添加onload属性可以在模板加载完后执行一个表达式。
    要记住,使用ng-include时angularjs会自动创建子作用域。如果你想使用某个特定的作用域,例如ControllerA的作用域,必须在同一个DOM元素上添加ng-controller=”ControllerA”指令,这样当模板加载完成后,不会像往常一样从外部作用域继承并创建一个新的子作用域。

示例:

1
2
3
<div ng-include="/myTemplateName.html" ng-controller="MyController" ng-init="name='world'">
Hello {{name}}
</div>

  • ng-switch
    这个指令和ng-switch-when及on=”propertyName”一起使用,可以在propertyName发生变化时渲染不同指令到视图中。在下面例子中,当person.name是Ari时,文本域下面的div会显示,并且这个人会获得胜利:
1
2
3
4
5
<input type="text" ng-model="person.name"/>
<div ng-switch on="person.name">
<p ng-switch-default> And the winner is</p>
<h1 ng-switch-when="Ari">{{person.name}}</h1>
</div>

注意,在switch被调用之前我们用ng-switch-default来输出默认值。

  • ng-repeat

ng-repeat用来遍历一个集合或为集合中的每个元素生成一个模板实例。集合中的每个元素都会被赋予自己的模板和作用域。同时每个模板实例的作用域中都会暴露一些特殊的属性。
\$index:遍历的进度。
\$first:当元素是遍历的第一个时值为true。
\$middle:当元素处于第一个和最后元素之间时值为true。
\$last:当元素是遍历的最后一个时值为true。
\$even:当\$index值时偶数时值为true。
\$odd:当\$index值是奇数时值为true。
下面的例子展示了如何用\$odd和\$even来制作一个红蓝相间的列表。记住,JavaScript中数组的索引从0开始,因此我们用!$even和!$odd来将\$even和\$odd的布尔值反转。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<ul ng-controller="PeopleController">
<li ng-repeat="person in people" ng-class="{even:!$even,odd:!$odd}">
{{person.name}} lives in {{person.city}}
</li>
</ul>
.odd{
background-color:blue;
}
.even{
background-color:red;
}
angular.module('myApp',[])
.controller('PeopleController',function(){
$scope.people=[
{name:"Ari",city:"San Francisco"},
{name:"Erik",city:"Seattle"}
];
});
  • ng-view
    ng-view指令用来设置将被路由管理和放置在HTML中的视图的位置。

  • ng-controller

  • ng-if
    使用ng-if指令可以完全根据表达式的值在DOM中生成或移除一个元素。如果赋值给ng-if的表达式为false,那对应的元素将会从DOM中移除,否则对应元素的一个克隆将被重新插入DOM中。
    ng-if同ng-show和ng-hide指令最本质的区别是,它不是通过CSS显示或隐藏DOM节点,而是真正生成或移除节点。
    当一个元素被ng-if从DOM中移除,同它关联的作用域也会被销毁,而且当它重新加入DOM中时,会通过原型继承从它的父作用域生成一个新的作用域。
    同时有一个重要的细节需要知道ngIf重新创建元素时用的是它们编译后的状态。如果ng-if内部的代码加载之后被jquery修改过,那么当ng-if的表达式值为false时,这个DOM元素会被移除,表达式再次成为true时这个元素及其内部的子元素会被重新插入DOM,此时这些元素的状态会是它们的原始状态,而不是它们上次被移除时的状态。也就是说无论用jquery的.addClass添加了什么类都不会存在。

1
2
3
4
5
6
<div ng-if="2+2===0">
won`t see this DOM node,not even in the source code
</div>
<div ng-if="2+2==4">
Hi,I do exist
</div>
  • ng-init
    ng-init指令用来在指令被调用时设置内部作用域的初始状态。
    ng-init最常见的使用场景是:对于任何需要健壮结构的场景,请在控制器中用数据模型对象来设置状态。
1
2
3
<div ng-init="greeting='hello';person='world'">
{{greeting}}{{person}}
</div>
  • 双大括号
    双大括号语法是angularjs内置的模板语法,它会在内部\$scope和视图之间创建绑定。基于这个绑定,只要\$scope发生变化,视图就会随之自动更新。
    事实上它也是指令,虽然看起来并不像,实际上它是ng-bind的简略形式,用这种形式不需要创建新的元素,因此它常被用在行内文本中。
    注意,在屏幕可视的区域内使用双大括号会导致页面加载时未渲染的元素发生闪烁,用ng-bind可以避免这个问题。

    1
    2
    3
    <body ng-init="greeting='HelloWorld'">
    {{greeting}}
    </body>
  • ng-bind
    尽管可以在视图中使用双大括号模板语法,我们也可以通过ng-bind指令实现同样的行为。

1
2
3
<bod ng-init="greeting='HelloWorld'">
<p ng-bind="greeting"></p>
</bod>
  • ng-cloat
    除使用ng-bind来避免为渲染元素闪烁,还可以在含有双大括号的元素上使用ng-cloak指令:
1
2
3
<body ng-init="greeting='Helloworld'">
<p ng-cloak>{{greeting}}</p>
</body>

ng-cloak指令会将内部元素隐藏,直到路由调用对应的页面时才显示出来。

  • ng-bind-template
    同ng-bind指令类似,ng-bind-template用来在视图中绑定多个表达式。
1
2
<div ng-bind-template="{{message}}{{name}}">
</div>
  • ng-model
    ng-model指令用来将input、select、textarea或自定义表单控件同包含它们的作用域中的属性进行绑定。它可以提供并处理表单验证功能,在元素上设置相关的CSS类(ng-valid、ng-invalid等),并负责在父表单中注册控件。
    它将当前作用域中运算表达式的值同给定的元素进行绑定。如果属性并不存在,它会隐式创建并将其添加到当前作用域中。
    我们应该始终用ngModel来绑定\$scope上一个数据模型内的属性,而不是\$scope
    上的属性,这可以避免在作用域或后代作用域中发生属性覆盖。
1
2
<input type="text" ng-model="modelName.someProperty"/>
上面的例子展示了如何正确地考虑和使用ngModel。
  • ng-show/ng-hide
    ng-show和ng-hide根据所给表达式的值来显示或隐藏HTML元素。当赋值给ng-show指令的值为false时元素会被隐藏,类似地,当赋值给ng-hide指令的值为true时元素也会被隐藏。
    元素的显示或隐藏是通过移除或添加ng-hide这个CSS类来实现的。ng-hide类被预先定义在了angularjs的CSS文件中,并且它的display属性的值为none。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <div ng-show="2+2==0">
    2+2 isn`t 0,don`t show
    </div>
    <div ng-show="2+2==4">
    2+2 is 4,do show
    </div>
    <div ng-hide="2+2==3">
    2+2 isn`t 3,don`t hide
    </div>
    <div ng-hide="2+2==4">
    2+2 is 4,don`t hide
    </div>
  • ng-change
    这个指令会在表单输入发生变化时计算给定表达式的值。因为要处理表单输入,这个指令要和ngModel联合起来使用。

1
2
3
4
5
6
7
8
9
10
11
<div ng-controller="EquationController">
<input type ="text" ng-model="equation.x" ng-change="change()"/>
<code>{{equation.output}}</code>
</div>
angular.module('myApp',[])
.controller('EquationController',function($scope){
$scope.equation={};
$scope.change = function(){
$scope.equation.output=parseInt($scope.equation.x)+2;
};
});
  • ng-from
    ng-from用来在一个表单内部嵌套另一个表单。普通的HTML
    标签不允许嵌套,但ng-form可以。
    这意味着内部所有的子表单都合法时,外部的表单才会合法。这对于用ng-repeat动态创建表单是非常有用的。
    由于不能通过字符插值来给输入元素动态地生成name属性,所以需要将ng-form指令内每组重复的输入字段都包含一个外部表单元素内。
    下面的CSS类会根据表单的验证状态自动设置:
  • 表单合法时设置ng-valid;
  • 表单不合法时设置ng-invalid;
  • 表单未进行修改时设置ng-pristion;
  • 表单进行过修改时设置ng-dirty;
    angular不会将表单提交到服务器,除非它指定了action属性。要指定提交表单时调用哪个JavaScript方法,使用下面两个指令中的一个。
  • ng-submit:在表单元素上使用
  • ng-click:在第一个按钮或submit类型的输入字段上使用。
    示例:
    展示如何通过服务器返回的JSON数据动态生成一个表单。我们用ng-loop来遍历从服务器取回的所有数据。由于不能动态生成name属性,而我们又需要这个属性做验证,所以在循环的过程中会为每一个字段都生成一个新表单。
    由于angularjs中用来取代
    的ng-form指令可以嵌套,并且外部表单在所有子表单都合法之前一直处于不合法状态,因此我们可以在动态生成子表单的同时使用表单验证功能。
    下面先看一下我们硬编码的JSON数据,把他假设成是从服务器返回的。
1
2
3
4
5
6
7
8
9
10
11
angular.module('myApp',[])
.controller('FormController',function($scope){
$scope.fields=[
{placeholder:'Username',isRequired:true},
{placeholder:'Password',isRequired:true},
{placeholder:'Email(optional)',isRequired:false}
];
$scope.submitFrom=function(){
alert('it works!');
};
});

下面用这些数据生成一个有验证功能的动态表单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<form name="signup_form" ng-controller="FormController" ng-submit="submitForm()" novalidate>
<div ng-repeat="field in fields" ng-form="signup_form_input">
<input type="text" name="dynamic_input" ng-required="field.isRequired" ng-model="field.name" placeholder="{{field.palceholder}}"/>
<div ng-show ="signup_form_input.dynamic_input.$dirty && signup_form_input.dynamic_input.$invalid">
<span class="error" ng-show="signup_form_input.dynamic_input.$error.required">
The field is required
</span>
</div>
</div>
<button type="submit" ng-disabled="signup_form.$invalid">
submit All
</button>
</form>
input.ng-invalid{
border:1px solid red;
}
  • ng-click
    ng-click用来指定一个元素被点击时调用的方法或表达式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <div ng-controller="CounterController">
    <button ng-click="count=count+1" ng-init="count=0">
    Increment
    </button>
    count:{{count}}
    <button ng-click="decrement()">
    </button>
    </div>
    angular.module('myApp',[])
    .controller('CounterController',function(){
    $scope.decrement=function(){
    $scope.count=$scope.count-1;
    };
    });
  • ng-select
    ng-select用来将数据同HTML的

  • 数组作为数据源
    用数组中的值做标签
    用数组中的值作为选中的标签
    用数组中的值做标签组
    用数组中的值作为选中的标签组

  • 对象作为数据源
    用对象的键值做标签
    用对象的键值作为选中的标签
    用对象的键值作为标签组
    用对象的键值作为选中的标签组
    示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div ng-controller="CityController">
<select ng-model="city" ng-option="city.name for city in cities">
<option value="">Choose City</option>
</select>
Best City:{{city.name}}
</div>
angular.module('myApp',[])
.controller('CityController',function($scope){
$scope.cities = [
{name:'Seattle'},
{name:'San Francisco'},
{name:'Chicago'},
{name:'New York'},
{name:'Boston'}
];
});
  • ng-submit
    ng-submit 用来表达式同onsubmit时间进行绑定。这个指令同时会阻止默认行为(发送请求并重新加载页面),除非表单不含有action属性。
    示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<form ng-submit="submit()" ng-controller="FormController">
Enter text and hit enter:
<input type="text" ng-model="person.name" name="person.name"/>
<input type="submit" name="person.name" value="Submit"/>
<code>people={{people}}</code>
<ul ng-repeat="(index,object) in people">
<li>{{object.name}}</li>
</ul>
</form>
angular.module('myApp',[])
.controller('FormController',function($scope){
$scope.person={name:null};
$scope.people=[];
$scope.submit=function(){
if($scope.person.name){
$scope.people.push({name:$scope.person.name});
$scope.person.name='';
}
};
});
  • ng-class
    使用ng-class动态设置元素的类,方法是绑定一个代表所有需要添加的类的表达式。重复的类不会添加。当表达式发生变化,先前添加的类会被移除,新类会被添加。
    下面的例子会用ng-class在一个随机数大于5时将.red类添加到一个div上:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div ng-controller="LotteryController">
<div ng-class="{red:x>5}" ng-if="x>0">
You won!
</div>
<button ng-click="x=generateNumber()" ng-init="x=0">
Draw Number
</button>
<p>Number is: {{x}}</p>
</div>
.red {
background-color:red;
}
angular.module('myApp',[])
.controller('LotteryController',function($scope){
$scope.generateNumber = function(){
return Math.floor((Math.random()*10)+1);
};
});
  • ng-attr-(suffix)
    当angularjs编译DOM时会查找两个花括号some expression内的表达式。这些表达式会被自动注册到\$watch服务中并更新到\$digest循环中,成为它的一部分:
1
2
3
4
<h1> Hello {{someExpression}}</h1>
<svg>
<circle cx="{{cx}}"></circle>
</svg>

运行上面的代码会抛出一个错误,指出我们有一个属性。可以用ng-attr-cx来解决这个问题。注意,cx位于这个名称的尾部。在这个属性中,通过用双大括号来写表达式,达到前面提到的目的。

1
2
3
<svg>
<circle ng-attr-cx="{{cx}}"></circle>
</svg>

热评文章