Others

.run

使用run进行一个简单的rootScope绑定。

  1. angular.module('myApp', [])
  2. .run(function($rootScope) {
  3. $rootScope.name = "World";
  4. });

$parse

eg1

  1. <div ng-app="MyApp">
  2. <div ng-controller="MyController">
  3. <input type="text" ng-model="expression" />
  4. <div>{{ParsedValue}}</div>
  5. </div>
  6. </div>
  1. angular.module("MyApp",[])
  2. .controller("MyController", function($scope, $parse){
  3. $scope.$watch("expression", function(newValue, oldValue, context){
  4. if(newValue !== oldValue){
  5. var parseFunc = $parse(newValue);
  6. $scope.ParsedValue = parseFunc(context);
  7. }
  8. });
  9. });
  10. //输入1+1,ParseValue显示2

eg2

  1. <div ng-app="MyApp">
  2. <div ng-controller="MyController">
  3. <div>{{ParsedValue}}</div>
  4. </div>
  5. </div>
  1. angular.module("MyApp",[])
  2. .controller("MyController", function($scope, $parse){
  3. $scope.context = {
  4. add: function(a, b){return a + b;},
  5. mul: function(a, b){return a * b}
  6. }
  7. $scope.expression = "mul(a, add(b, c))";
  8. $scope.data = {
  9. a: 3,
  10. b: 6,
  11. c: 9
  12. };
  13. var parseFunc = $parse($scope.expression);
  14. $scope.ParsedValue = parseFunc($scope.context, $scope.data);
  15. });
  16. //结果为45

$parse服务根据$scope.context中提供的上下文解析$scope.expression语句,然后使用$scope.data数据填充表达式中的变量注意,如果把$scope.expression中的c换成4,那么结果就是30,所以得到45结果。
**

$interpolate

  1. <body ng-app="myApp">
  2. <div ng-controller="MyController">
  3. <input ng-model="to" type="email" placeholder="Recipient" />
  4. <textarea ng-model="emailBody"></textarea>
  5. <pre>{{ previewText }}</pre>
  6. </div>
  7. </body>
  1. angular.module('myApp', [])
  2. .controller('MyController',
  3. function ($scope, $interpolate) {
  4. $scope.to = 'ari@fullstack.io';
  5. $scope.emailBody = 'Hello {{ to }},\n\nMy name is Ari too!';
  6. // Set up a watch
  7. $scope.$watch('emailBody', function (body) {
  8. if (body) {
  9. var template = $interpolate(body);
  10. $scope.previewText =
  11. template({ to: $scope.to });
  12. }
  13. });
  14. });

image.png
当textarea变化时,previewText才能依据二者变化;只变email,此时previewText不被触发。

使用config/factory来完成更方便的写法

  1. angular.module('emailParser', [])
  2. .config(['$interpolateProvider', function($interpolateProvider) {
  3. $interpolateProvider.startSymbol('__');
  4. $interpolateProvider.endSymbol('__');
  5. }])
  6. .factory('EmailParser', ['$interpolate', function($interpolate) {
  7. return {
  8. parse: function(text, context) {
  9. var template = $interpolate(text);
  10. return template(context);
  11. }
  12. };
  13. }]);
  14. 使用:
  15. angular.module('myApp', ['emailParser'])
  16. .controller('MyController', ['$scope', 'EmailParser',
  17. function($scope, EmailParser) {
  18. // 设置监听
  19. $scope.$watch('emailBody', function(body) {
  20. if (body) {
  21. $scope.previewText = EmailParser.parse(body, {
  22. to: $scope.to
  23. });
  24. }
  25. });
  26. }]);
  1. 由于我们将表达式开始和结束的符号都设置成了__,因此需要将HTML修改成用这个符号取代{{ }}的版本
  2. <div id="emailEditor">
  3. <input ng-model="to"
  4. type="email"
  5. placeholder="Recipient" />
  6. <textarea ng-model="emailBody"></textarea>
  7. </div>
  8. <div id="emailPreview">
  9. <pre>__ previewText __</pre>
  10. </div>

过滤器

调用过滤器

{{ name | uppercase }}

  1. app.controller('demo',[$scope,$filter,function($scope,$filter){
  2. $scope.name = $filter('lowercase')('ARI');
  3. }])

自定义过滤器

注意input在哪作为参数传入。

  1. app.controller('demo',[ ])
  2. .filter('price',function(){
  3. return function(input) {
  4. price = Number(input).toFixed(2);
  5. return price;
  6. }
  7. })
  8. {{ '123' | price }}
  9. // 123.00

内置过滤器

currency

{{ 123 | currency }}来将123转化成货币格式。

date

{{ today | date:'medium' }} <!-- Aug 09, 2013 12:09:02 PM -->
date后为过滤器参数,不同参数可以格式化成不同的格式。

filter

filter过滤器可以从给定数组中选择一个子集,并将其生成一个新数组返。
{{ ['Ari','Lerner','Likes','To','Eat','Pizza'] | filter:'e' }}

  1. {{ [{
  2. 'name': 'Ari',
  3. 'City': 'San Francisco',
  4. 'favorite food': 'Pizza'
  5. },{
  6. 'name': 'Nate',
  7. 'City': 'San Francisco',
  8. 'favorite food': 'indian food'
  9. }] | filter:{'favorite food': 'Pizza'} }}
  10. <!-- [{"name":"Ari","City":"SanFrancisco","favoritefood":"Pizza"}] -->
  1. {{ ['Ari','likes','to','travel'] | filter:isCapitalized }}
  2. <!-- ["Ari"] -->
  3. $scope.isCapitalized = function(str) {
  4. return str[0] == str[0].toUpperCase();
  5. }; //isCapitalized函数的功能是根据首字母是否为大写返回true或false,filter过滤出返回true的情况。

json

{{ {'name': 'Ari', 'City': 'SanFrancisco'} | json }}

orderBy

  1. {{ [{
  2. 'name': 'Ari',
  3. 'status': 'awake'
  4. },{
  5. 'name': 'Q',
  6. 'status': 'sleeping'
  7. },{
  8. 'name': 'Nate',
  9. 'status': 'awake'
  10. }] | orderBy:'name' }}
  11. <!--
  12. [
  13. {"name":"Ari","status":"awake"},
  14. {"name":"Nate","status":"awake"},
  15. {"name":"Q","status":"sleeping"}
  16. ]
  17. -->

可连续过滤

{{ 'ginger loves dog treats' | lowercase | capitalize }}
先全转换为小写,再首字母大写。

表单验证

P30
1. 必填项
验证某个表单输入是否已填写,只要在输入字段元素上添加HTML5标记required即可:
<input type="text" required />
2. 最小长度
验证表单输入的文本长度是否大于某个最小值,ng-minleng= “{number}”:
<input type="text" ng-minlength="5" />
3. 最大长度
验证表单输入的文本长度是否小于或等于某个最大值,ng-maxlength=”{number}”:
<input type="text" ng-maxlength="20" />
4. 模式匹配
使用ng-pattern=”/PATTERN/“来确保输入能够匹配指定的正则表达式:
<input type="text" ng-pattern="/^([a-zA-Z0-9_-]+)$/" />
5. 电子邮件
验证输入内容是否是电子邮件,只要像下面这样将input的type设置为email即可:
<input type="email" name="email" ng-model="user.email" />
6. 数字
验证输入内容是否是数字,将input的类型设置为number:
<input type="number" name="age" ng-model="user.age" />
7. URL
验证输入内容是否是URL,将input的类型设置为 url:
<input type="url" name="homepage" ng-model="user.facebook_url" />
8. 自定义验证

9. 在表单中控制变量
表单的属性可以在其所属的$scope对象中访问到,而我们又可以访问$scope对象,因此
JavaScript可以间接地访问DOM中的表单属性。借助这些属性,我们可以对表单做出实时(和
AngularJS中其他东西一样)响应。
(注意,可以使用下面的格式访问这些属性。)
formName.inputFieldName.property
ng-show = "form.start_at.$dirty"

 未修改的表单
这是一个布尔属性,用来判断用户是否修改了表单。
如果未修改,值为true,如果修改过值为false:
form.$pristine
 修改过的表单
只要用户修改过表单,无论输入是否通过验证,该值都返回true:
form.$dirty
 合法的表单
这个布尔型的属性用来判断表单的内容是否合法。
如果当前表单内容是合法的,下面属性的值就是true:
form.$valid
 不合法的表单
这个布尔属性用来判断表单的内容是否不合法。
如果当前表单内容是不合法的,下面属性的值为true:
form.$invalid
 错误
这是AngularJS提供的另外一个非常有用的属性:$error对象。
它包含当前表单的所有验证内容,以及它们是否合法的信息。用下面的语法访问这个属性:
formName.inputfieldName.$error
ng-show="form.description.$error.maxlength"
如果验证失败,这个属性的值为true;如果值为false,说明输入字段的值通过了验证。
10. 一些有用的CSS样式

  1. .ng-pristine {}
  2. .ng-dirty {}
  3. .ng-valid {}
  4. .ng-invalid {}

它们对应着表单输入字段的特定状态。
当某个字段中的输入非法时,.ng-invlid类会被添加到这个字段上。
当前例子中的站点将对应的CSS样式设置为:

  1. input.ng-invalid {
  2. border: 1px solid red;
  3. }
  4. input.ng-valid {
  5. border: 1px solid green;
  6. }

自定义验证

  1. <form name="signup_form" novalidateng-submit="signupForm()">
  2. <fieldset>
  3. <input type="text"
  4. placeholder="Desired username"
  5. name="username"
  6. ng-model="signup.username"
  7. ng-minlength="3"
  8. ng-maxlength="20"
  9. ensure-unique="username" required />
  10. <small class="error"
  11. ng-show="signup_form.username.$error.maxlength">
  12. Your username cannot be longer than 20 characters</small>
  13. <small class="error"
  14. ng-show="signup_form.username.$error.unique">
  15. That username is taken, please try another</small>
  16. <button type="submit" class="button radius">Submit</button>
  17. </fieldset>
  18. </form>
  1. app.directive('ensureUnique',function($http){
  2. return {
  3. require: 'ngModel',
  4. link: function(scope, ele, attrs, c){
  5. $scope.$watch(attrs.ngModel,function(n) {
  6. if(!n) return;
  7. $http({
  8. method: 'POST',
  9. url: '/api/check/' + attrs.ensureUnique,
  10. data: {
  11. field: attrs.ensureUnique,
  12. value: scope.ngModel
  13. }
  14. }).success(function(data){
  15. c.$setValidity('unique', data.isUnique);
  16. //'unique'用于"signup_form.username.$error.unique"
  17. //ng-maxlength同理为"signup_form.username.$error.maxlength"
  18. }).error(function(data){
  19. c.$setValidity('unique', false);
  20. });
  21. });
  22. }
  23. };
  24. });

ngMessages

  1. <div class="error" ng-messages="signup_form.name.$error" ng-messages-multiple>
  2. // 加上ng-messages-multiple后可以同时显示多个错误
  3. <div ng-message="required">Make sure you enter your name</div>
  4. <div ng-message="minlength">Your name must be at least 3 characters</div>
  5. <div ng-message="maxlength">Your name cannot be longer than 20 characters</div>
  6. </div>

指令

<my-directive></my-directive>
<div my-directive></div>
<div class="my-directive"></div>
<!--directive:my-directive-->

restrict

元素(E)、属性(A)、类(C)或注释(M)
_

scope

在构造自定义指令时也可以创建新的子作用域。

  1. template: '<a href="{{ myUrl }}">{{ myLinkText }}</a>'
  1. <div my-directive
  2. my-url="http://google.com"
  3. my-link-text="Click me to go to Google">
  4. </div>
  5. //给指令添加两个属性,这两个参数会成为指令内部作用域的属性。
  1. 想普通控制器一样写controller
  2. controller: function($scope) {
  3. // => 错误!!!
  4. $scope.someProperty === "needs to be set";
  5. }
  6. 像下面一样直接赋值?
  7. scope: {
  8. // 这样也行不通
  9. someProperty: 'needs to be set'
  10. }

正确做法是像给函数传递参数一样,通过属性来设置值。

@

**这个绑定策略告诉AngularJS**
**将DOM中some-property属性的值复制给新作用域对象中的someProperty属性。**

  1. scope: {
  2. someProperty: '@' //默认情况下映射是some-property属性。
  3. }
  4. scope: {
  5. someProperty: '@someAttr' //此时被绑定的属性名是some-attr而不是some-property。
  6. }

Attention

  1. <input type="text" ng-model="myUrl" />
  2. <div my-directive
  3. some-attr="{{ myUrl }}"
  4. my-link-text="Click me to go to Google">
  5. </div>
  6. //这种myUrl绑定可以正常工作。
  1. <div my-directivesome-attr="{{ myUrl }}"
  2. my-link-text="Click me to go to Google">
  3. </div>
  4. 还有下面这段代码:
  5. template: '<div>\
  6. <input type="text" ng-model="myUrl" />\
  7. <a href="{{myUrl}}">{{myLinkText}}</a>\
  8. </div>'
  9. //myUrl写在指令内部无法正常工作

=

双向数据绑定

  1. <label>Their URL field:</label>
  2. <input type="text" ng-model="theirUrl">
  3. <div my-directive
  4. some-attr="theirUrl"
  5. my-link-text="Click me to go to Google"></div>
  1. angular.module('myApp', [])
  2. .directive('myDirective', function() {
  3. return {
  4. restrict: 'A',
  5. replace: true,
  6. scope: {
  7. myUrl: '=someAttr', // 经过了修改
  8. myLinkText: '@'
  9. },
  10. template: '<div><label>My Url Field:</label><input type="text" \ ng-model="myUrl" /> \
  11. <a href="{{myUrl}}">{{myLinkText}}</a></div>'
  12. };
  13. });
  14. //修改外面的input或者template里的input都一起变化。

父子控制器

修改父级对象中的someBareValue会同时修改子对象中的值,但反之则不行。
子控制器是复制而非引用someBareValue。
当子中有``someBareValue,且someBareValue的值不为引用类型时,``父的``someBareValue改变时子的显示不变化,子的改变也不影响父。
但如果子中没有``someBareValue的话,子的显示会和父一起改变。

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

上述情况,子$scope中修改属性也会修改父$scope中的这个属性。

ng-repeat作用域

 $index:遍历的进度(0...length-1)。
 $first:当元素是遍历的第一个时值为true。
 $middle:当元素处于第一个和最后元素之间时值为true。
 $last:当元素是遍历的最后一个时值为true。
 $even:当$index值是偶数时值为true。
 $odd:当$index值是奇数时值为true。

  1. <li ng-repeat="person in people track by $index" ng-class="{even: !$even, odd: !$odd}">
  2. {{person.name}} lives in {{person.city}}
  3. </li>
  4. //调换顺序or删除插入时,$index容易出bug

指令详解

  1. angular.module('myApp', [])
  2. .directive('myDirective', function() {
  3. return {
  4. restrict: String, //以什么形式声明EACM
  5. priority: Number, //优先级,在同一元素上,是否先被调用,默认0(ngRepeat是内置指令优先级最高的)
  6. terminal: Boolean, //如果为true,则同一个元素上的其他指令的优先级高于本指令的将停止。
  7. template: String or Template Function: function(tElement, tAttrs) (...},
  8. templateUrl: String,
  9. replace: Boolean or String,
  10. scope: Boolean or Object,
  11. transclude: Boolean,
  12. controller: String or
  13. function(scope, element, attrs, transclude, otherInjectables) { ... },
  14. controllerAs: String,
  15. require: String,
  16. link: function(scope, iElement, iAttrs) { ... },
  17. compile: // 返回一个对象或连接函数,如下所示:
  18. function(tElement, tAttrs, transclude) {
  19. return {
  20. pre: function(scope, iElement, iAttrs, controller) { ... },
  21. post: function(scope, iElement, iAttrs, controller) { ... }
  22. }
  23. // 或者
  24. return function postLink(...) { ... }
  25. }
  26. };
  27. });

scope参数

scope:true;
当scope设置为true时(默认情设置为true),会从父作用域继承并创建一个新的作用域对象。

scope:{ };
scope设置为一个空对象{},如果这样做了,指令的模板就无法访问外部作用域了

绑定策略

@ (or @attr)
本地作用域属性:使用@符号将本地作用域同DOM属性的值进行绑定。
指令内部作用域可以使用外部作用域的变量。
= (or =attr)
双向绑定:通过=可以将本地作用域上的属性同父级作用域上的属性进行双向的数据绑定。
就像普通的数据绑定一样,本地属性会反映出父数据模型中所发生的改变。
& (or &attr)
父级作用域绑定:通过&符号可以对父级作用域进行绑定,以便在其中运行函数。
意味着对这个值进行设置时会生成一个指向父级作用域的包装函数。
要使调用带有一个参数的父方法,我们需要传递一个对象,这个对象的键是参数的名称,值
是要传递给参数的内容。

  1. oneVal: '@oneVal', // 相当于“值复制”
  2. twoVal: '=twoVal', // 相当于“引用复制”
  3. threeVal: '&threeVal' // 绑定父作用域中的方法