欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

宁皓网 AngularJS 基础 这个是不是版本太旧 不必要看了 有大用

AngularJS 是 Google 开发的一套开源的 JavaScript 框架,在 Google 内部,很多项目都用到了这个框架。

来自  https://ninghao.net/course/2034#info



下面的目的是创建本地的angular.js的文档,但是我不能成功的运行,可能是版本不对吧

https://github.com/angular/angular.js 

# git clone   https://github.com/angular/angular.js.git        #把angular.js克隆到本地

# cd angular.js             #进入到这个目录

# yarn                            #我这里使用了yarn,没用npm install,因为 npm install 老是安装不起来

# npm install -g grunt-cli             #需要全局安装 grunt-cli 吗? 上面yarn已经安装好了吧 

# sudo npm install grunt --save-dev      #需要当前目录下安装grunt吗?

# grunt package webserver # 这行命令会使用事先编写好的脚本去做一些事情 ... (package )比如去下载需要的一些东西,( webserver )最后会创建一个服务器, 为什么我运行会失败?

 http://localhost:8000/build/docs/api            #此时可以打开本地版本的 angularjs.org 了 ... 可以查看 angularjs 的 api ,还有一些相关的文档 ... 为什么我这边不能打开















1)介绍

AngularJS  ( https://angularjs.org  )是 Google 开发的一套开源的 JavaScript 前端框架。我们可以用它来创建 Single Page Applications ,简称 SPAs ... 单页面的应用程序。AngularJS 非常适合去创建 CRUD 类型的应用,就是应用跟创建,读取,更新和删除数据有关。

使用框架的好处就是我们可以少写很多代码,不过要按照框架设计好的结构跟模式 ... 所以我们得明白在框架提供的一些组件是干什么的。在 AngularJS 这个框架里,你会经常看到 module,controller,directive,filter,service 这些东西。在这个课程里,我们会介绍这些东西是什么,怎么样去使用它们。

比如怎么样使用 directive,也就是指令 ,让 html 拥有新的功能,用 filter 过滤器,去格式化要显示的数据 ... 怎么样给表单绑定数据 ... 验证用户在表单元素上输入的东西,显示自定义的错误提示。怎么样定义可以在其它的地方重复使用的服务 ... 再看几个 AngularJS 自带的服务,比如用 $http 服务,向服务端发送请求 ...

学习这个课程你需要一些 JavaScript 的基础知识,你可以先看一下宁皓网的 JavaScript 基础教程 ... 另外也可以学习一下 Backbone 相关的课程,这样会更好的理解 JavaScript ...

来自  https://ninghao.net/video/2035#info


2)创建本地版本的 angularjs.org


https://angularjs.org

angularjs.org 是 Angularjs 的官方网站,你可以查看 Angularjs 的 api 还有相关的说明文档。不过在国内,我们很可能访问不到这个网站,你需要采取一些手段。或者,也可以在自己的电脑上创建一个本地版本的 angularjs.org ....

打开 github ... 搜索一下 angularjs.org ... 先把这个版本库克隆到本地,然后再去执行一些命令就可以了。

复制一下版本库的地址 ... 打开 命令行工具 ... Mac 可以使用终端,Windows 用户可以使用 Powershell 或者命令提示符 ... 进入到你想保存这个项目的地方 ... 这里我要把它放到桌面上 .. 然后输入 git clone ... 后面加上复制的版本库的地址 .. 回车执行一下 ..

git clone https://github.com/angular/angular.js.git

ls 查看一下当前的目录 ... 进入到这个 angular.js 里面 ...

cd angular.js

然后使用 npm 去安装一下项目依赖的一些东西 ... 我们得先安装好 node 才能使用这个命令 ... 用的命令是 npm install ...

npm install ...

完成以后 ... 再输入 grunt package webserver ... 这行命令会使用事先编写好的脚本去做一些事情 ... 比如去下载需要的一些东西,最后会创建一个服务器,使用这个地址,我们就可以访问到 Angularjs 的文档了 ...

打开浏览器,输入 localhost:8000/build/docs/api ... 这样就可以打开本地版本的 angularjs.org 了 ... 可以查看 angularjs 的 api ,还有一些相关的文档 ...

来自  https://ninghao.net/video/2036#info


基础

3)引导应用


ngApp 是我们第一个要知道的指令,在 html 文档的元素里面,使用这个指令,意思就是,告诉 Angular,这个元素还有它里面的东西属于应用的一部分。也就是在这个元素还有它里面,我们可以去使用 Angular 提供的功能。

一般这个这个指令会作为 body 或者 html 元素的一个属性来使用。 比如在这里,我们可以把这个指令放到 html 这个元素的上面 .. 输入 ng-app .. 这里的意思就是告诉 Angular ,html 这个元素是我们的应用的根元素 .. 这样在这个文档里面,我们就可以使用 Angular 的功能了。

比如在这里用一个绑定,先输入两组花括号 ... 在这个花括号里面,先试几个表达式, 1 + 1 ... 保存 .. 在浏览器上你会看到算出来的结果 ... 2 * 5 ... 结果是 10 ... "hello" + " ninghao!" 结果就是把这两个字符串连接到了一起 ...

下面我们可以把这个 ng-app 放到一个其它的地方 ... 输入一组 div ... 然后把 ng-app 作为它的一个属性 ... 再去掉 html 元素上面的 ng-app ... 保存 ...

你会看到,浏览器上面会直接输出我们输入的东西,因为现在 ng-app 这个指令放到了这个 div 元素里面,Angular 会认为这个元素还有它里面的东西才是应用的一部分 ... 我们把这个绑定放到这个 div 里面 ... 再保存 .. 现在又可以显示表示式算出来的结果了。

https://docs.angularjs.org/api/ng/directive/ngApp

来自  https://ninghao.net/video/2037#info


4)创建一个模块:Modules


我们可以把一个应用程序分割成不同的模块,每个模块里面都可以包含控制器,服务,过滤器,还有指令这些东西。在设计大型应用的时候,可以按照应用的不同的功能,去设计不同的模块,也可以把重复使用的组件做成模块,比如指令,过滤器这些东西,然后我们可以再创建一个应用级别的模块,让它去依赖这些设计好的模块,这个模块里面,可以包含初始化的代码。

模块就是 Angular 用来把相关的代码打包,放到一个名字里面。

创建模块

创建一个模块可以使用 angular 的 module 这个方法,输入 angular.module ... 这个方法的第一个参数就是模块的名字 ... 我们先创建一个叫 myApp 的模块 ... 它的第二个参数是这个模块依赖的其它的模块,也就是如果想让这个模块拥有在其它模块上定义的功能,得把这些模块的名字放到这里 ... 这个参数是一个数组,如果没有依赖的模块,我们可以用一个空白的数组 ...

angular.module('myApp', []);

注意在定义模块的时候,我们必须要指定这个第二个参数 ... 去掉这个空白的数组 ... 这行代码的意思就是去找到在其它文件里面定义的一个叫 myApp 的模块 ... 意思就是去使用这个模块,而不是去定义一个模块。定义模块必须要指定这个模块的依赖,没有依赖的东西,就用一个空白的数组。

用模块引导

有了这个模块以后,我们就可以告诉 Angular ,用这个模块去引导应用,打开 index.html ,在这个文档的 html 元素上面,用了一个 ng-app ,这个属性现在没有指定值,这是自动引导应用的方法,如果你想使用一个特定的模块去引导应用,需要把这个模块的名字,作为这个属性的值 ....

<html ng-app="myApp">

现在我们创建了一个空白的模块叫 myApp ,并且使用这个模块去引导应用程序,这个模块还不能做什么,在下面的视频里我们去在这个模块里面添加一个控制器。

来自  https://ninghao.net/video/2038#toc


5)使用控制器:Controllers


我们可以使用控制器去给视图提供要显示的数据,这个数据可以来自应用程序的后台数据库。在上一个视频里我们定义了一个模块,在这个模块里面,可以去添加控制器。打开 app.js ...

在这个 module 方法的后面,继续使用一个 .controller 方法 ... 或者也可以这样,先把这个模块交给一个变量 ... 比如叫它 myApp ..

var myApp = angular.module('myApp', []);

然后再使用 myApp 的 .controller 方法 ... 它的第一个参数是给我们给控制器起的名字 ... 比如去创建一个叫 UserController 的控制器,控制器的名字里面,每个词的第一个字母用大写,一般命名控制器就是使用这样的形式,先是可以描述这个控制器作用的一个词儿,我这里就是 User,后面再加上 Controller 这个词儿。

它的第二个参数就是这个控制器要做的事情 ... 用一个匿名函数 ... 在这里,可以简单的用一个 console.log ... 在控制器上输出点文字 ...

myApp.controller('UserController', function () {
console.log('Hello');
});

保存 ... 再回到 index.html ... 想要使用控制器,可以先找到一个元素 ... 比如这里先新建一个 div 标签 ... 然后再这个元素上面使用 ngController 这个指令 ... 这个指令作为这个元素的一个属性,就是 ng-controller ... 它的值就是要用到的控制器的名字 ... 输入 UserController ...

这样在这个 div 标签里面,我们就可以使用 UserController 这个控制器里的东西了。先保存一下 ... 打开浏览器的控制台,你会看到 UserController 控制器在控制台上输出的文字 ... Hello ...

这里要注意一下,在 index.html 这个文档里面,我用到了 myApp 这个模块来引导应用,你会发现 ng-app 的值就是这个模块, 这样我们才能在它里面,使用这个模块拥有的东西,比如我们定义在这个模块上的 UserController 控制器。

来自   https://ninghao.net/video/2039


6)从控制器里提供视图显示的数据:$scope


$scope 是控制器跟视图之间的中介,它可以让我们在控制器还有视图之间交互数据。所有在视图上设置的变量,可以通过 $scope 在控制器上访问到,所有添加到 $scope 上的数据也都可以在视图上显示出来。

先打开 app.js ,在之前定义的 UserController 这个控制器里面,我们先添加一个变量 ... var name = "wanghao" ...

myApp.controller('UserController', function ($scope) {
var name = 'wanghao';
});

然后再打开 index.html ... 在这个使用了 UserController 控制器的 div 元素里面,用一个绑定 ... 输入两组花括号 ... 要显示的东西是在这个控制器里的 name 这个变量 ... 保存 ... 在浏览器上并没有显示出控制器里的 name 这个变量的值 ... 因为这个变量属于控制器内部本地的变量 ... 不能用到视图上。想要让这个数据在视图上可用,可以通过 $scope 这个东西 ...

先把它注入到控制器里面 ... 让它作为这个匿名函数的一个参数 ... $scope ... 然后我们再把 name 添加到 $scope 的上面 ... 因为添加到 $scope 上面的东西,我们都可以在视图上访问到 ...

myApp.controller('UserController', function ($scope) {
$scope.name = 'wanghao';
});

保存 ... 在浏览器上会显示出 name 的值 ... 这里我们也可以把一个对象添加到 $scope 上面,比如添加一个叫 user 的对象 ... 先让它等于一个空白的对象 ... 然后在这个对象里面,再添加一个 name 属性 ... 它的值设置成 wanghao ... 再添加一个叫 email 的属性 ... 它的值是 wanghao@ninghao.net ..

myApp.controller('UserController', function ($scope) {
$scope.user = {};
$scope.user.name = 'wanghao';
$scope.user.email = 'wanghao@ninghao.net';
});

回到 index.html ... 再改造一下 ... 这里输出 user 的 name 属性 ... 前面再加上点文字 ... 另起一行 ... 再输出 user 的 email ...

<div ng-controller="UserController">
<p>用户名:{{ user.name }} </p>
<p>E-mail:{{ user.email }}</p>
</div>

保存 ... 在浏览器上,会显示出从控制器那里设置的 user 对象里面的属性的值。

来自  https://ninghao.net/video/2040#info


7)在控制器上定义方法


我们可以在控制器的 $scope 上面添加一个方法,然后在视图上去使用这个方法。打开 app.js ... 还是在 UserController 这个控制器里面,在 $scope 上面添加一个方法,这个方法可以放到 user 这个对象的上面 ... 方法的名字是 subscribe ...

$scope.user.greet = function () {}

这个方法要做的事情就是,可以在控制台上输出点的文字 ... 先用一个 $scope.user.name 输出 user 对象里的 name 的值 ... 中间加上点文字 ... 最后再用一个 $scope.user.email 输出 user 的 email 的值 ...

$scope.user.subscribe = function () {
console.log($scope.user.name + ", 您订阅的新闻将会发送到:" + $scope.user.email);
};

保存 ... 再打开 index.html ... 我们可以在应用了 UserController 控制器的这个元素里面,去使用刚才定义的方法 ... 先添加一个按钮 ... 可以使用 button 标签 ... 按钮上的文字是 订阅 ... 然后在这个元素上面,再用一个 ngClick 指令 ... 用它我们可以指定元素被点击以后要做的事情 ... 在这个 button 元素上面,用一个 ng-click 属性 ... 它的值设置成 user.subscribe() ... 意思就是,当点击这个按钮以后,就去执行在 user 上面定义的 subscribe() 这个方法 ...

<button ng-click="user.subscribe()">订阅</button>

保存 ... 回到浏览器 ... 打开控制台 ... 然后点击 订阅 这个按钮 ... 这样会执行 user 里面的 subscribe 方法,也就会在控制台上输出一些文字 ...

来自  https://ninghao.net/video/2041


8)双边数据绑定


Two-Way Data Binding ,双边数据绑定,其实就是模型发生变化以后也会更新视图的显示,模型在视图上改变以后,也会去更新模型。先打开 index.html ,在这个使用了 UserController 控制器的元素里面,我们把模型里的数据显示到了这里,这是一个单边的数据绑定,也就是,模型里的数据只是显示在了这里,模型发生变化,这里的显示也会发生变化 ...

下面,我们再试一下双边的绑定,先在这里添加两个文本框元素 ... 用一个 input 标签 ... type 的值是 text,表示这是文本类型的 input ,在这个元素上,我们用一个 ng-model ,也就是 Angulsr 的 ngModel 指令 ... 它的值设置成 user.name ... 把 user 的 name 属性的值作为这个文本框的值 ...

再添加一个文本框元素 ... 同样用一个 ng-model ... 它的值我们设置成 user.email ..

<input type="text" ng-model="user.name">
<input type="text" ng-model="user.email">

保存 ... 在浏览器里预览一下 ... 在这两个表单元素上,都会显示出各自的值 ... 现在我们可以去修改一下它们里面的值 ... 用户名这里输入 xiaoxue ... 你会看到在下面绑定的 user.name 这里,会立即显示出我们在文本框里输入的内容 ....

再修改一下这个 E-mail ... xiaoxue@ninghao.net ... 同样,在所有绑定了 user 的 email 的地方,会立即显示出修改之后的内容 ... 这个就是两边的数据绑定 ... 我们只是简单的用了一个 ng-model 指令,就可以实现这个功能。

再点一下 订阅 这个按钮 ... 在控制台上,你会看到,显示的文字里面,在绑定的数据的地方,也会使用修改之后的数据 ...

来自  https://ninghao.net/video/2042#info


指令

9)指令:Directives


directive,可以翻译成指令,我们可以直接在 HTML 文档上面使用 Angular 自带的或者自己定义的指令来扩展 html 的功能,比如有些指令可能给元素绑定事件,当发生跟使用的指令相关的事件以后,就去执行指定的动作,像我们前面介绍过的 ng-click 指令,它就是在元素上发生点击事件以后,去执行这个指令指定的动作,类似的还有 ngKeydown,ngKeypress,ngMouseover 等等。

一般指令都可以重复的使用。我们可以把指令当成 HTML 的标签,属性,CSS 类或者评论来用。不过最常见的还是作为 HTML 标签的属性来使用指令,指令原本的名字都是小写的 ng 后面加上指令的名字 ... 名字的首字母是大写的 ... 不过用到 html 上面,我们可以使用小写的 ng 加上一个连接符,也就是一个减号 ... 后面是指令的名字(可以用小写的名字) ...

如果你在乎 html 标签验证的话,也可以在指令的前面加上一个 data- ... 这样作为属性应用的指令会认为是有效的 html 标签的属性。

https://docs.angularjs.org/api/ng/directive

来自 https://ninghao.net/video/2043


10)显示数据列表:ngRepeat


在控制器里我们可能从应用的后台提供出来一个数组数据或者是一个对象,我们可以在视图上面循环的输出数组里面的每一个项目,或者对象里的所有的 key 还有 value ..

先打开 app.js ... 在这里我们再给定义的 myApp 这个模块去添加一个控制器 ... 输入 myApp.controller ... 这个控制器可以叫它 ShowController ... 在这个控制器里,在 $scope 上面,添加点数据 ... $scope.shows 等于 ... 它的值是一个数组 ... 数组里的每个项目都是一个对象 ...

现在,我们想把这些数据输出到视图上 ... 先回到 index.html ... 添加一个元素 ... 上面再用一个 ng-controller ,指定一下对应的控制器 ... 这里就是 ShowController ...

在这个 div 标签里面,我们想去显示一个数据的列表 ... 这个列表我打算放到一个无序列表里面,所以先用一个 ul 标签 ... 在这个标签里面,再用一个 li 标签, 在这个 li 标签上面, 再使用 Angular 的 ngRepeat 指令 ... 添加一个 ng-repeat 属性 ... 它的值可以使用特定的一种形式 ... show in shows ... 它的意思就是,把 ShowController 里面的 shows 这个数组里的每一个项目分别交给一个叫 show 的变量 ... 这样每次循环的时候, 我们都可以使用这个 show 来引用,shows 这个数组里的对象的值 ... 注意每次循环都会包含这个 li 标签 ...

在这个标签里面,再用一个绑定,去输出 show 的 title 属性的值 ... 用两组花括号 ... 花括号里面再用一个 show.title ...

保存 ... 在浏览器上,会输出一个列表 ... 列表里的项目就是在 ShowController 里面的 shows 这个数组里的项目的 title 属性的值 ... 打开浏览器的开发者工具 ... 你会看到,列表的每个项目都会放到一个 li 标签里面。

https://docs.angularjs.org/api/ng/directive/ngRepeat

来自  https://ninghao.net/video/2044

11)动态应用 CSS 类:ngClass


ngClass 这个指令可以让我们在 HTML 的元素上面动态的应用一些 css 类。先打开 app.js ,在 ShowController 这个控制器里面,shows 这个数组里的对象,我又添加了一个 subscribe 属性,它的值表示的是当前用户是否订阅了这部电视剧,我们可以根据这个属性的值,去在电视剧标题列表的上面添加一个 css 类 ..

先在 app 的目录下面,再新建一个目录 ... 命名为 css ... 在这个目录下面,添加一个样式表,叫做 style.css ... 在这个样式表里,定义一个 css 类 ... 叫做 .subscribe ... 它的样式就是把文字的颜色设置成绿色 ..

.subscribe {
color: green;
}

回到 index.html ,先把 style.css 链接过来 ... 然后在这个列表标签上面,添加一个 ng-class 属性 ... 也就是使用 angular 的 ngClass 这个指令 ... 它的值可以是一个字符串,数组或者是一个对象,如果是对象的话,对象的 key 就是 class 的名字,对应的值决定了是否要添加这个 class,也就是如果值是 true,就去添加 class ,如果是 false 就去掉这个 class 。

这里我们要使用的 class 的名字是 subscribe ,也就是在 style.css 里面定义的那个 css 类。它的值设置成 show.subscribe ... 它表示的就是在 ShowController 这个控制器里,shows 数组的项目的 subscribe 这个属性的值 ...

<div ng-controller="ShowController">
<ul>
<li ng-repeat="show in shows" ng-class="{subscribe: show.subscribe}">
{{ show.title }}
</li>
</ul>
</div>

保存 ... 在浏览器上你会发现,有些列表项目里的文字会变成绿色,这是因为这个列表项目的 subscribe 这个属性的值是 true,这样也就会在这个列表上面应用一个叫 subscribe 的 css 类 ... 这个类里定义的样式就是让文字变成绿色 ...

右键点击,审查元素 ... 你会看到,这个项目上面的 class 属性里面,会有一个 subscribe 类 ...

再回到 index.html ... 我们在每个项目上面添加一个复选框的表单元素 .. 然后在上面绑定一个数据 ... 用一个 ng-model ... 值设置成 show.subscribe ... 保存 ... 现在每个列表的上面都会显示一个复选框。项目的 subscribe 的值如果是 true 的值,这个复选框就是被勾选的状态 ...

下面,我们先取消一个被勾选的复选框 ... 你会看到,文字会立即变成原来的黑色 .. 因为这样会把当前这个项目的 subscribe 这个属性的值设置成 false ... 也就会去掉添加到这个项目上的 subscribe 类 ... 如果再重新勾选一下的话 ... 又会把这个 css 类添加到这个项目的上面 ...

https://docs.angularjs.org/api/ng/directive/ngClass

来自 https://ninghao.net/video/2045


12)动态显示或隐藏元素:ngShow ngHide


应用里面有些元素你可能希望在特定的条件下显示或者隐藏起来,我们可以根据不同的情况,使用 ngShow ,还有 ngHide 这两个指令。ngShow 可以在表达式计划出来的结果为 true 的时候显示元素,在 false 的时候隐藏元素,ngHide 正好相反,会在计算结果是 true 的时候隐藏元素,在 false 的时候显示元素。

现在,这个列表项目里面都有两个小图标 ,一个表示未勾选的小图标,另一个表示已经勾选上的小图标。 在 subscribe 的值是 true 的时候,我们希望隐藏这个未勾选的图标,显示已勾选的小图标。如果项目的 subscribe 的值是 false 的话,显示未勾选,隐藏已勾选小图标。

在这个未勾选的小图标元素上面,我们使用一个 ngHide 指令 ... 用一个 ng-hide 属性 ... 它的值就是 subscribe 的值 ...

<span class="glyphicon glyphicon-unchecked" ng-hide="show.subscribe"></span>

然后在这个已勾选的小图标的元素上,使用一个 ng-show ... 它的值,也设置成 subscribe 的值 ...

<span class="glyphicon glyphicon-check" ng-show="show.subscribe"></span>

保存 ... 你会看到,在复选框打勾的项目上,会显示这个已勾选的小图标,在复选框上没打勾的项目上,会显示表示未勾选的这个小图标 ... 我们可以再点击一下这个勾选了的复选框,这样会改变 subscribe 的值,把 true 换成了 false ... 也就会把已勾选的小图标隐藏起来,把表示未勾选的小图标显示出来 ...

来自  https://ninghao.net/video/2046#info


13)过滤器:filter


filter 就是过滤器,它其实是一种格式化数据的小工具,比如你在服务端那里得到了一些日期类型的数据,原本这个数据的显示格式可能不是你想要的,这样你就可以在视图上输出这些日期数据的时候,应用一个 date 过滤器,然后去设计一下自己想要的日期格式。

Angular 自带了一些过滤器,我们也可以自己去定义新的过滤器 ... 这些过滤器可以用到 Angular 的其它组件里面,比如控制器,服务,或者指令等等。


来自  https://ninghao.net/video/2047#info


14)日期:date


date 这个过滤器可以把日期类型数据转换成你想要的格式,在我的 ShowController 里面,shows 里面的每个项目都有一个叫 updated 的属性,它的值是时间戳,也就是从 1970 年 1 月 1 号开始到一个时间之间的秒数。

再打开 index.html ... 我们已经把这个 updated 属性的值绑定到了这里 ... 就是这个更新于后面,使用双花括号形式的绑定。在浏览器上会显示出这个属性里的值。下面我们可以使用 date 这个过滤器去改造一下这个时间的显示。

不过在改造前,我们需要转化一下这个时间戳,因为 JavaScript 只认识 从 1970 年 1 月 1 号到一个时间之间的毫秒数,所以,我们需要把这个秒数转化成毫秒 ... 1 秒 等于 1000 毫秒,所以,需要让这个属性的值先乘以 1000 ... 然后再去应用 date 过滤器 .. 在后面输入一个竖线 ... 接着是过滤器的名字 ... date .. . 保存 ..

默认会用这样的形式来显示日期跟时间 ... 前面是月份的英文简写,然后是日子,接着是年 ... 我们完全可以按照自己的需求去定制这个时间的显示的形式。Angular 也提供了几种预先定义好的显示日期跟时间的形式 ... 这个形式都有一个名字 ... 默认你看到的应该是 medium 形式 .. 我们再试一下其它的 ...

在 date 后面加上一个冒号 ... 然后再试一下 'short' .. 保存 ... 这样会用月日年,加上时间,还有表示上午跟下午的字符来显示 ..

再试一下 longDate ... 会用完整的英文的月份,加上日子还有年度 ....

再试一下 shortTime ... 这种格式只会显示几点 ...

这些预先定义的格式如果不能满足我们的需求,也可以自己去定制一种显示的格式。 比如我想用年月日,再加上时间的形式 .. 先输入一个 yyyy ,它表示的是四位数的年 ... 中间一个横线,再加上两个大写的 M ,它表示用两位数字表示月份 .. 后面再加上一个横线,然后用两个小写的 d 表示日子 ...

再用一个逗号 ... 用两位数字表示小时,可以使用两个大写的 H,它可以用 24 进制来表示时间 ... 中间用一个冒号,再去连接表示分钟的字符 ... 用两个小写的 m ...

{{ show.updated * 1000 | date: 'yyyy-MM-dd, HH:mm' }}

保存 ... 现在显示的日期跟时间就是我们自己设计好的形式 ... 四位数字的年,两位数字的月份还有日期 ... 另外还有一个 24 小时进制的时间 ...

还有很多表示日期跟时间的用法,你可以参考 Angular 官方网站上面的 date 过滤器的相关文档。

https://docs.angularjs.org/api/ng/filter/date


来自  https://ninghao.net/video/2048#info

过滤器

15)限制数量:limitTo


使用 limitTo 这个过滤器,我们可以去限制一个字符串显示的字符数,也可以限制一个数组显示的项目数。比如在这个电视剧列表里,我想限制电视剧介绍内容的显示的字数。先看一下 app.js ... 这个介绍的内容属性 description 这个属性 ..

再打开 index.html .. 在这里我绑定输出了 description 里的内容 ... 我们可以在这加上一个 limitTo 过滤器 ... 后面先输入一个竖线 ... 然后是过滤器的名字 limitTo .. 冒号的右边就是表示限制的数量 .. 比如我们要限制只显示 200 个字符 ... 输入 200 ... 保存 ...

浏览器上会显示限制字数之后的电视剧的描述 ...

下面我们再用 limitTo 过滤器,去限制一下这个电视剧列表的显示的数量 ... 在这个 ng-repeat 里面,加上一个竖线 .. 然后是 limitTo .. 冒号 ... 接着是要限制显示的数量 ... 比如输入 3 .. 保存 .. . 你会看到浏览器上只会显示三个项目 ... 输入 2 .. 再保存 ... 现在只会显示两条 .. .

这个数字也可以是一个负数,这样会从后往前去限制显示 ... 比如输入 -3 ... 保存 ... 现在显示的是原来列表里面的倒数的三个项目 .. 也就是最后的三个项目 ...

<li ng-repeat="show in shows | limitTo: 3">

这个限制的数量我们可以让它跟一个文本字段绑定到一块,这样就可以通过这个字段去控制限制的数量了。在上面添加一个 input 元素 ... 类型是 number ,数字类型的文本字段 ... 给它绑定一个模型 ... 比如叫它 limit ...

然后在 limitTo 这个过滤器的后面 ... 去使用这个 limit ...

<input type="number" ng-model="limit">
<li ng-repeat="show in shows | limitTo: limit">

保存 ... 现在浏览器上没有显示任何的列表项目 ... 因为 limit 这个字段还没有值 ... 在这里字段里输入一个数字,或者点击右边的增加还有减少的按钮 ... 你会发现,项目显示的数量,会根据这个字段里的值 ... 3 就会显示三个项目 ... 如果是 -3 ,显示的就是倒数三个项目 ...

我们也可以给这个字段一个初始的值 ... 打开 app.js ,找到 ShowController 这个控制器 ... 在这里,我们去设置一下 limit 的值 ...

$scope.limit = 5;

保存 .. 现在,这个列表页面默认会显示 5 个项目 ...

来自  https://ninghao.net/video/2049#info


16)过滤:filter


想要在一个列表里面找到包含特定内容的项目,可以使用 filter 这个过滤器,比如在这个电视剧列表里,找出包含 game 的列表项目 ... 我们也可以自己去定义比较的条件,比如找出评分大于 9 分的项目。

打开 index.html ... 在这个列表元素里面,我们可以继续应用过滤器 ... 用一个竖线 ... 加上一个叫 filter 的过滤器 ... 它的值可以是一个字符串,也可以是一个对象,如果是字符串的话,Angular 就会给我们找到包含这个字符串内容的列表项目 ...

这里我们先设置成 'game' ... 注意这个内容的周围是有引号的 ... 保存 ... 在浏览器上会立即显示出包含 game 的项目 ... 因为这个项目的 name 这个属性的值里面,包含了 game 这个字符串,所以它会显示出来 ...

<li ng-repeat="show in shows
| limitTo: limit
| orderBy: 'rate': true
| filter: 'game'
">

再试一下,家庭 ... 保存,显示的项目是 摩登家庭 ... 这个项目的 title 属性里面包含了 家庭 这两个字儿 .. 想找出不包含指定内容的项目,可以在这个内容的前面,加上一个 ! 号 .. 现在显示的项目,就是项目的内容里面就是不包含 家庭 这两个字儿的项目 ...

对象
如果你只想针对特定的的属性去查找 ... 比如我们只想找出项目的 title 属性包含特定内容的项目 ... 这里我们可以使用一个对象 ... 对象里的 key 就是要过滤的那个属性的名字 ... 先把它设置成 title ... 跟它对应的值,就是要查找的内容 ... 设置成 'game' ... 保存 ... 没有显示东西 ... 这是因为我们现在要找的东西是在 title 这个属性里的值 ...

<li ng-repeat="show in shows
| limitTo: limit
| orderBy: 'rate': true
| filter: {title: 'game'}
">

再改成 '游戏' ... 结果就是 权力的游戏,因为只有这个项目的 title 属性的值里面,包含 游戏 这两个字儿。

绑定
在这个项目的上面,我们再加上一个文本框 ... 给它绑定一个模型 .. 用一个 ng-model ... 它的值设置成 query ... 然后我们再把它设置成要查找的内容 ... 这样在这个文本框里输入的内容,就跟这个要查找的内容绑定在了一起 ...

<input type="text" ng-model="query" placeholder="搜索">
<li ng-repeat="show in shows
| limitTo: limit
| orderBy: 'rate': true
| filter: {title: query}
">

保存 ... 在这个搜索的文本框里,我们可以输入要查找的电视剧的标题 ... 输入 游戏 .. 会显示 权力的游戏 ... 输入 黑帮 ... 会显示 浴血黑帮 ...

 来自  https://ninghao.net/video/2050#toc


17)过滤 #2


filter 这个过滤器也可以让我们自己去定义过滤比较的条件 .. 比如我们要找出评分大于 9 分的电视剧 ... 先打开 index.html ... 在这个列表元素上面,再用一个 filter ... 它的表达式这个参数是一个对象 ... 对象的 key 是 rate ... 也就是电视剧的评分这个属性 ... 它的值先设置成 9 ...

<li ng-repeat="show in shows
| limitTo: limit
| orderBy: 'rate': true
| filter: {title: query}
| filter: {rate: 9}
">

保存 ... 现在浏览器上显示的结果是,电视剧的列表里面,评分属性的值里包含 9 的项目,比如这里 8.9 这个评分的 冰血暴 也在这里出现了 ... 我们想要的是,项目的评分属性的值要大于 9 ...

打开 app.js ... 在 ShowController 这个控制器里面,先去定义一个方法 ... 把它放到 $scope 的上面,这样我们可以在视图上使用这个方法 ... 方法的名字可以叫它 comparator ... 这个方法支持两个参数 ... 第一个参数是 actual ,它表示项目的属性真正的值 ... 第二个参数是 expected ... 它的值就是我们要查找的那个值 ...

在这个方法里,我们可以返回比较的条件返回 ture 的项目 ... 用一个 return ... 要比较的是 actual > expected; 意思就是,如果项目真正的值大于我们期待的值,就把这个项目返回来 ...

$scope.comparator = function(actual, expected) {
return actual > expected;
};

保存 ... 回到 index.html ... 我们需要在这个 filter 过滤器的上面,使用这个方法 ... 加上一个冒号 ... 然后是这个方法的名字 ... comparator ...

<li ng-repeat="show in shows
| limitTo: limit
| orderBy: 'rate': true
| filter: {title: query}
| filter: {rate: 9}:comparator
">

再保存一下 ... 现在,浏览器上面,显示的项目,就是项目的 rate 评分属性的值,大于 9 的所有的项目 ...

来自  https://ninghao.net/video/2051#info


表单

18)表单:Form


一个表单就是使用了一个 form 标签,它的里面可以有各种各样的表单元素,比如文本字段,E-mail 字段,文本区域等等。在 angular 的应用里面,创建一个表单,可以先用一个 form 标签 ... 这个标签在 angular 里面同样是一个指令 ...

这个指令会去创建一个 ngModelController 的实例,这个实例可以解析,格式化,还有验证表单,它会去跟踪属于它的所有的表单元素,还有这些元素的状态,比如是否有效,有没有被碰过等等。

下面我们先试一下 ... 打开 index.html ,在这里输入一组 form 标签 ... 然后再给这个表单添加一个 name 属性,去指定一下它的名字,这个名字就是实例化之后的 ngModelController 的实例的名字。这里我们叫它 userForm ..

<form name="userForm"></form>

这里我们可以把它绑定在视图上,输出来看一下 ... {{ userForm }} .. 保存 ... 会输出一个 json 格式的数据 .. 为了让它显示的更清楚一些,我们用一组 pre 标签包装一下输出的内容 ... 然后在这里再应用一个 json 过滤器 ...

<pre>{{ userForm | json}}</pre>

上面有一些属性 ... $error 这里会包含表单的错误信息 ... $name 是表单的名字 ... 这里就是 userForm ... $dirty ,这个属性可以表示这个表单有没有被碰过,如果被碰过,比如用户在这个表单里面的元素上输入了内容 .. 这个属性的值就会是 true ... 现在它的值是 false ... 如果表单没有被碰过的话,$pristine 这个属性的值会是 true ...

$valid 表示表单是否有效 .. 比如在验证表单遇到错误,它的值就会是 false ,$invalid 这个属性的值就会是 true ... 如果提交了表单,这里的 $submitted 属性的值,就会变成 true ...

https://docs.angularjs.org/api/ng/directive/form

https://docs.angularjs.org/api/ng/type/form.FormController

来自 https://ninghao.net/video/2052#info


19)添加表单元素


一个 input 元素,如果上面用到了 ngModel 指令,并且添加了 name 属性为元素起了名字,这个 input 元素也会包含一个 ngModelController 的实例,并且会用它的名字作为表单上的 ngModelController 实例的一个属性。这样属于表单的控制器实例就可以统一的管理属于它的所有的表单元素了。

下面,我们给 userForm 这个表单去添加一个元素 .. 用一个 input 元素 ... 类型可以是 email ... 保存 .. 在页面上会显示一个文本框,类型是 email ,输出的 userForm 的内容没有什么变化 ... 因为我们还没有给这个元素起名字,而且也没有给它绑定模型 ...

先给它添加一个名字 ... 设置一下 name 属性的值 ... 比如可以叫它 userEmail ... 再用一个 ng-model 来绑定数据,可以叫做 user.email。

<input type="email" name="userEmail" ng-model="user.email">

保存 ... 现在,输出的 userForm 的内容就会发生变化 ... 这里你会看到一个 userEmail ... 它里面又包含了一些东西,$validators,$parsers,$formatters ,这里还有一些已经有值的属性,$untouched,没有碰过,它的值是 true ,表示我们还没有动过这个 Email 字段。

这个 $untouched 跟 $pristine 有点区别,$pristine 表示一点都没有碰过。 我们可以演示一下,在这个文本框里输入一个 email ... 注意现在我还没有离开这个文本框,也就是它还在 focus,焦点的状态 ... 再看一下 userEmail 里的 $untouched 属性,它的值仍然是 true ,不过 $pristine 的值,已经变成了 false ...

$pristine 还有 $dirty ,在用户一开始与表单交互的时候,它们的值就会发生变化,而 $untouched 和 $touched ,只有在用户离开焦点状态以后,它们的值才会发生变化。

我们再看一下 userForm 的这几个属性,你会发现,$pristine 的值也变成了 false ,因为这个表单里的元素已经被动过了,这样它的 $dirty 的值就会变成 true 。

来自 https://ninghao.net/video/2053#info


20)表单状态 class


Angular 提供了一些跟表单状态相关的 css 类,会根据情况应用在表单还有它的元素上面,我们可以使用这些 css 类,动态的去为表单应用一些样式。

再看一下之前我们创建的这个表单,打开浏览器的开发者工具 ... 选择 Elements 选项卡 ... 然后选中这个 form 表单元素 ... 在这个标签上面,应用的 class 有 ng-pristine ,它表示表单还没有被动过 .. 另外还有 ng-valid,还有一个 ng-valid-email ,表示表单没有错误 ... 验证有效 ...

在这个表单元素里面的这个 email 字段上面也用了一些 class,ng-pristine,ng-untouched 等等 ... 下面我们在这个表单里面的 email 字段里输入点东西 ..

注意当我们按下按键以后,form 标签上的 .ng-pristine 这个类就不会了,因为我们已经动过了这个表单,同样,email 字段上的 .ng-pristine 这个类也不见了,换成了 .ng-dirty, .. 另外在 form 标签还有这个 email 字段上面的 .ng-valid 类,会换成 .ng-invalid ,因为现在在这个 email 字段里输入的东西,不符合要求,我们需要输入一个正确的 email 地址 ..

要加上一个 @ 符号 ... 跟着一个域名 .. 现在 .ng-invalid 类又会换成 .ng-valid ,因为验证表单的输入,没有发现错误。

现在这个表单里面只有一个表单元素,如果按下回车的话,就会提交这个表单 ... 这样在这个 form 标签上面,会应用一个 .ng-submitted 类 ...

鼠标点击一下空白的地方,或者按下 tab 键,离开这个 email 字段 ... 这样这个元素上面的 .ng-untouched 类,就会换成 .ng-touched ..

来自  https://ninghao.net/video/2054#info


21)验证


Angular 允许我们在表单上使用 HTML5 的验证属性来验证表单,比如 required ,minlength 或者 maxlength,另外 Angular 也会验证 input 元素的类型,email,url,date,number 等等 ... 在这些表单元素上面发生的错误,会放到 $error 的上面。

在使用 Angular 的验证表单功能之前,我们可以先关掉浏览器自带的验证功能,比如在这个 email 字段里面,先输入点内容,然后再按一下回车 ... 浏览器会自动验证我们填写的内容,这里会显示电子邮件地址里面要包含 @ 符号 ...

打开 index.html ,在这个表单上面,我们添加一个 novalidate ... 这样会关掉浏览器的验证功能,回到浏览器,输入点东西,再按一下回车 ... 虽然现在我们输入的是一个不合格的邮件地址,浏览器也不会有任何的提示,因为我们关掉了它本身的验证功能。

<form name="userForm" novalidate>

注意在下面输出的 userForm 里面,$error 这个属性里会包含表单里面验证出来的不合格的东西,现在这里有一个 email ,表示 email 这个验证规则,在这里会有一个出现错误的表单元素,$name 就是这个元素的名字,就是表单里面的 userEmail 这个字段出现了错误 ...

我们再找到下面的 userEmail ... 在它里面,也会包含一个 $error , 你会看到现在 email 的值是 true ,表示这个元素里的内容不符合 email 这个验证规则。 下面,我们可以再输入一个正确的 email 地址 ...

现在, 这里的 $error 里面就没有东西了,说明所有的表单元素都验证通过 ... 下面 userEmail 里面的 $error 也没有东西,表示这个元素现在符合所有的验证的要求。

来自  https://ninghao.net/video/2055


22)验证规则


这个视频我们再看一些表单元素的验证规则 ... 如果一个元素是必填项,可以在这个元素上面,添加一个 required 属性 ... 或者你也可以使用 ng-required ... 在这个 email 字段上面,加上一个 required ..

限制一个字段的最小的长度,可以使用 minlength 属性 ... 比如我们要求 email 这个字段,至少得是 5 个字符 ... 把 minlength 的值,设置成 5 ... 也可以把这个 minlength 换成 angular 特有的 ng-minlength ..

限制字段的最大的长度,用的是 maxlength ... 我们让这个 email 字段的最大长度是 50 个字符 ... 把这个属性的值设置成 50 ...

保存 ... 回到浏览器 ... 先查看一下这个 email 字段 .. 你会发现,在这个元素上面,会有一些 css 类 ... ng-invalid-required ... 之所以有这个 class ,是因为 email 是一个必填的字段,我们还没有在这个字段上输入内容,这样 required 这个规则验证无效,也就会在这个字段的元素上面添加一个 ng-invalid-required ... 如果验证通过的话,augular 会把这个类换成 ng-valid-required ...

再看一下这个 $error 属性,现在是 required ... 意思是必填这个规则在某个字段上验证失败了 .. 我们在这个字段上面输入点内容 ... 这样错误里面就不会再有 required 了 ... 现在的错误是 email ,因为我们输入的内容不是一个有效的 email 地址 ...

后面加上一个 @ ... 现在是有效的 email 地址,不过现在又不满足 minlength 这个规则,因为字符数还没有达到最少的要求,也就是 5 个字符 ... 再换一个长一点的有效的 email 地址 ...

现在,$error 里面就没有东西了。因为表单里的所有的元素通过了所有的验证规则。

这里有个地方要注意一下,就是 maxlength 这个规则,因为我们用的是标准的 html 属性,所以这个字段不会让我们输入超过这个属性值的字符 .. 如果你打算让 $error 里面出现 maxlength 的错误,你可以在字段上面,使用 ng-maxlength 这个属性来设置最大可以输入的字符。这样如果用户输入的字符超过了这个属性设置的最大的字符,在这个 $error 上面,就会出现 maxlength ...

来自  https://ninghao.net/video/2056#info


23)自定义错误提示


我们可以为每个表单元素的每个验证的规则自定义错误的提示信息。在这个 email 元素的下面,我们先给 required 这个规则添加一个自定义的错误提示,当用户没有在这个字段里面输入内容的时候,会显示这个错误提示。

这个错误信息可以放到一个段落标签里面,在这个标签上可以使用 bootstrap 框架提供的两个 css 类,给它添加点样式 ... alert 还有 alert-danger

p.alert.alert-danger

要显示的错误提示是 email 字段是必填项 ... 现在这个错误提示会一直显示在页面上,我们需要让它在特定的条件下显示 ... 可以使用 ng-if ,ng-show 或者 ng-hide 这些指令 ... 这里我用一个 ng-if ...

它的值如果算出来的结果是 true 的话,才会显示这个元素 ... 我们把它的值设置成 userForm.userEmail.$error.required ... 如果 userEmail 这个字段的 required 验证规则验证失败的话,它的 $error 里面的 required 属性的值就会是 true ... 这样也就会显示这个错误提示 ...

<p class="alert alert-danger"
ng-if="userForm.userEmail.$error.required">
email 字段是必填项
</p>

保存 ... 在页面上会显示这个错误提示,因为我们还没有在这个字段里面输入内容 ... 在这个字段里输入点东西 ... 这样就不会在显示错误提示了 ...

这里我们可以再改进一下这个错误提示的显示 .. 比如我们想让这个错误提示在提交表单的时候,如果没有填写这个字段的内容,才显示出来 ... 或者,只有在动过这个字段以后,如果没有填写内容才显示这个错误 ...

在这个错误提示信息的周围,再用一组标签包装一下它 ... (ctrl + w),然后在这个标签上,再用一个 ng-if ... 显示这个元素的条件是 userForm.userEmail.$touched ... 它的意思是只有在动过这个 email 表单元素以后,才显示这个 div 元素里的内容 ...

后面加上两条竖线,表示 or ,也就是或者的意思 ... 再用一个条件 ... userForm.$submitted .. 提交表单以后,这个 $submitted 的值会变成 true ...

<div ng-if="userForm.userEmail.$touched || userForm.$submitted">
<p class="alert alert-danger"
ng-if="userForm.userEmail.$error.required">
email 字段是必填项
</p>
</div>

保存 ... 再到浏览器上看一下 .. 现在没有显示任何的错误 ... 点一下这个 email 字段 ... 然后再离开 ... 这样就会显示出这个提示,email 字段是必填项 .. 因为我们没有填写这个字段,同时也动过这个字段 ... 满足这两个条件就会显示这个错误提示 ...

再刷新一下 ... 然后再选中这个字段 ... 不填写内容 ... 按一下回车提交这个表单 ... 这样也会显示这个错误提示 ...

来自  https://ninghao.net/video/2057#info


服务

24)服务:service


service 的作用就是,为应用里面的其它的组件提供可以重复使用的功能。这里说的组件就是组成 Angular 的一些东西,比如指令,控制器,或者服务等等。service 这个名词在很多其它的地方也经常用到,中文可以翻译成服务,我们可以把它想像成是能做一些事情的东西。

控制器可以给视图提供数据,这个提取数据的活,我们就可以交给一个服务去做,同样,更新,存储,删除这些功能也都可以交给服务,这样不同的控制器都可以重复的去使用这些功能。

Angular 从头到尾只会创建一个服务的实例,所以服务是一种很好的让不同的组件之间相互沟通的方法。Angular 本身也自带了一些服务,你可以直接在应用里面使用它们,我们也可以根据需求去创建自己的服务。

https://docs.angularjs.org/api/ng/service

来自 https://ninghao.net/video/2058#info


25)自定义服务


下面我们用 factory 的方法来创建一个 service ,在我们应用里有两个控制器 UserController ,还有 ShowController ,这两个控制器可能都需要一些功能,就是去找到当前登录的用户,UserController 里面可能需要显示当前用户的名字,修改用户的档案等等,ShowController 有可能要用到当前用户的 id 去做一些事情,比如根据这个 id 找到当前用户喜欢的或者是订阅过的电视剧。

使用 service ,我们可以在控制器之间共享一些数据或者行为。这个视频我们通过一个简单的例子,来理解一下。

先在这个 app.js 里面新建一个 service ,输入 myApp.factory() ... 使用 factory 的方法来创建这个服务,另外还可以使用 service ,provider 的方法。使用哪种方法要看应用的需求或者个人喜好。

这个 factory 的第一个参数就是这个要创建的服务的名字 ... 我们可以叫它 User ,因为这个服务可以提供跟用户相关的一些功能。它的第二个参数就是服务可以做的事情。

myApp.factory('User', function () {};

我们先在一开始创建一个叫 user 的对象 ... var user = {}; 这里面包含一下简单的用户相关的内容 ...

var user = {
id: 1,
name: 'wanghao',
email: "wanghao@ninghao.net"
};

然后再创建一个函数 ... var _getUser = function() {}; 我们可以假设这个函数做了很多事情,比如到后台查询出当前用户的相关的信息。这里为了演示,我们让它简单的返回上面的 user 这个对象 ...

var _getUser = function () {
return user;
};

下面再创建一个函数 ... 可以叫它 _saveProfile ... 假设它做的事是去保存用户修改之后的个人档案 ... 同样保持简单,我们只是手工的去重新的设置一下 user 对象里面的相关的信息 ...

var _saveProfile = function () {
user.name = 'xiaoxue';
user.email = 'xiaoxue@ninghao.net';
};

最后在这个服务里面,我们需要返回这个服务要提供的功能或者数据 ... 用一个 return ... 返回一个对象 ... 这个服务我们想要提供 getUser 还有 saveProfile 这两个功能。 getUser 对应的是 _getUser ... saveProfile 对应的就是 _saveProfile ...

return {
getUser: _getUser,
saveProfile: _saveProfile
};

注入依赖

有了这个简单的服务以后,我们就可以在应用程序里面的其它组件里使用它了 ... 这里我们把它用在下面的这两个控制器里 ... 需要把这个服务作为控制器的依赖注入进来 ... 可以使用这个服务的名字 ... 作为一个参数 ... 这里要注入的,除了 $scope ,还有就是 User 这个服务 ...

在这个控制器里面,我们可以使用 User 服务提供的功能,比如使用它的 getUser 去得到当前的用户 ... 我们可以把它交给 $scope 的一个属性 ... $scope.user 等于 User.getUser();

然后在这个控制器里,再定义一个方法 ... 可以去提交用户修改个人档案的请求 ... $scope.submit = function() {} ... 在这个 submit 里面,可以使用 User 服务的 saveProfile() ...

myApp.controller('UserController', function ($scope, User) {
$scope.user = User.getUser();
$scope.submit = function () {
User.saveProfile();
};
});

下面,我们在 ShowController 这个控制器里,也用一下 User 这个服务 ... 比如我们也想在这个控制器里得到当前的用户 ... 先指定一下这个控制器的依赖 ... 一个是 $scope ... 还有就是 User ...

然后再把 User 服务的 getUser() 返回来的当前用户的相关的内容交给 $scope 上面的一个属性 ..

$scope.user = User.getUser();

HTML

保存 ... 再打开 index.html ... 添加一个标签 ... 上面使用 UserController 这个控制器 ... 标签里先添加一个标题 ... 然后可以再绑定输出 user.name ... 就是 UserController 这个控制器通过 User 服务的 getUser 得到的当前的用户的名字 ... 一个逗号,再输出用户的 email 地址 ...

然后另起一行,我们可以再用一个这个控制器里的 submit() 方法 ... 用一个 button 标签,按钮上面的文字是 提交 ... 上面加上 ng-click ... 点击这个按钮要做的事就是去执行 submit() 这个方法 ... 这个方法里面用到了 User 服务提供的 saveProfile ,它要做的就是去改变一下用户的相关信息。

<div ng-controller="UserController">
<h1>user</h1>
{{ user.name }},{{ user.email }}
<button ng-click="submit()">提交</button>
</div>

在下面,我再添加一组标签 ... 上面可以使用 ShowController 这个控制器 ... 里面添加一个标题 .. 再输出 user.name ... 还有 user.email ... 这两个东西表示的数据,也都是来自 User 服务的 getUser ...

保存 .... 在浏览器上,两个控制器里面,输出的用户名,还有用户的 email 地址是一样的 ... 在 UserController 这个控制器里面,我们还用了一个按钮 ... 点一下这个按钮 ... 这样会去执行这个控制器的 submit() 方法 ... 这个方法会用到 User 服务的 saveProfile .. 去改变用户的相关信息 ...

你会看到,绑定了用户相关信息的地方,会立即反映出修改之后的用户信息 ...

来自  https://ninghao.net/video/2059#info


26)$log


在调试应用程序的时候,我们经常会在控制台上输出一些信息,我们之前都是用 console.log 去做的,Angular 提供了一个 $log 服务,用这个服务,我们也可以在控制台上显示一些有用的信息,基本上跟 console.log 或者相关的像 console.info,console.error 做的事情是一样的。

使用 $log 的好处是,在有些不支持 console 的浏览器上不会显示错误,还有就是,我们可以通过一个叫 decorator() 的东西去更灵活的定制输出到控制台上的信息的显示。

在这个 app.js 里面,定义了一个模块,这个模块里面有一个控制器,就是 UserController ... 在 index.html 这个文档上面,我们用到了 UserController 这个控制器 ... 下面,我们可以在这个控制器里面,去使用 $log 这个服务 ...

我们需要把这个服务作为这个控制器的依赖的东西注入进来 ... 把 $log 作为这个匿名函数的一个参数 ... 这样在这个控制器里,就可以使用 $log 里面提供的一些方法了 ... 它里面有五个方法,分别可以使用不同的形式在控制台上输出信息 ...

log();
info();
warn();
error();
debug();

log() 可以在控制台输出日志类型的信息,info() 是信息类的内容,warn() 可以输出警告,error() 输出的是表示错误的提供信息,debug() 是调试信息。 下面,我们在这个控制器里面,分别使用这些方法,去在控制台上输出一些内容 ...

$log.log('用户登录');
$log.info('用户登录中...');
$log.warn('用户尝试登录的次数过多!');
$log.error('登录失败');
$log.debug('用户登录中...');

保存 ... 打开浏览器的控制台 ... 你会看到使用这些方法输出的东西 ... 用 log 方法输出的信息跟使用 console.log() 是一样的 ... 普通的黑色的文字 ... info() 方法输出的内容前面会带一个小 i 标志 ... warn() 方法是警告信息,它的前面是一个黄色的标志,里面有一个小叹号 ... error() 方法输出的错误信息,它的前面会有一个红色的错误符号 ... 用 debug() 方法输出的内容文字是蓝色的。

在这个浏览器的控制台上,我们可以过滤一下显示的不同类型的信息 ... 点击这个漏斗形状的小图标 .. 在右边这里,可以选择信息的类型 ... 比如点击 Errors ... 会过滤掉除了错误信息以外的所有的信息?。Warnings ... 显示的是警告类型的信息 ... Info 是提示类型的错误 ... Logs 显示的是日志 ... Debug 显示的是调试类型的信息 ...

点击前面的 All 会显示所有在控制台上输出的信息。

来自  https://ninghao.net/video/2060#info


27)关掉 $log 的调试信息


Angular 提供了一种方法,可以关掉在控制台上显示的所有的调试类型的信息,也就是使用 $log 的 debug() 方法输出的内容。回到 app.js ... 我们可以使用模块的 config() 方法去配置一下 ...

myApp.config();

给它一个匿名函数作为它的参数 ... 在这个函数里面,注入一个 $logProvider ... 使用它我们可以关掉在控制台上显示的调试类型的信息 ... 使用它的 debugEnabled 方法 ... 给它一个 false ...

myApp.config(function ($logProvider) {
$logProvider.debugEnabled(false);
});

注意,现在在浏览器的控制台上,最后一行就是用 $log 的 debug() 方法输出的内容 ... 保存 app.js  ... 你会发现,刚才显示在最后一行的那个 debug 类型的信息就不见了。因为我们关掉了它。

来自  https://ninghao.net/video/2061#info

28)$timeout


$timeout 这个服务其实就是 Angular 包装之后的 JavaScript 的 setTimeout ... 它可以让我们在指定的一个时间过后去执行一个动作。有点像是一个倒计时器。

我们还是通过一个简单的例子来理解一下这个服务的作用。在想要使用 $timeout 的地方,把它注入进来 ... 比如我们要在这个控制器里使用它,把 $timeout 作为这个函数的一个参数 ..

先在 $scope 上面定义一个方法 ... 叫作 gameOn ... 在这个方法里面, 先在控制台上输出一点文字 ... 使用 $log 服务的 log 方法 ... 输出的东西是 游戏开始 ...

$scope.gameOn = function () {
$log.log('游戏开始...');
}

然后我们再用 $timeout 这个服务 ... 在指定的时间过后去执行一个特定的动作 ... 先用一个 $timeout ... 它的第一个参数就是要执行的动作 ... 也就是一个函数,或者方法 ... 让它执行 $scope 上面的 gameOver ,一会儿我们再去定义这个 gameOver ... 逗号分隔开 ... 第二个参数就是一个倒计时的时间 .. 单位是毫秒 ... 比如我们想在 3 秒钟以后,去执行 gameOver ... 在这里就把这个时间设置成 3000 ... 1000 毫秒等于 1 秒钟 ...

$timeout($scope.gameOver, 3000);

下面再去定义 gameOver ... 同样把它放到 $scope 上面 ... 这个函数要做的就是在控制台上输出 游戏结束 这几个字儿 ...

$scope.gameOver = function () {
$log.info('游戏结束!');
};

保存 ... 再打开 index.html ... 这里我已经在一个元素上用到了 UserController 这个控制器 ... 在这个元素里面,添加一个按钮 ... 按钮上面的文字是 开始游戏 ... 在这个元素上面用一个 ng-click ... 点击它的时候,去执行 gameOn ...

<button ng-click="gameOn()">开始游戏</button>

保存 ... 打开浏览器,去预览一下,打开浏览器的控制台 ... 然后点击这个 开始游戏 按钮 ... 三秒钟以后,会在控制台上显示 游戏结束 ... 这是因为点击了按钮,会去执行 gameOn 这个函数 ... 它先会在控制台上输出 开始游戏 .... 然后 $timeout 这个服务开始计时 ... 在 3 秒以后,会执行一下 gameOver ... 这个函数做的事就是在控制台上输出 游戏结束 ...

来自  https://ninghao.net/video/2062#info


29)取消 $timeout


$timeout 服务在倒计时的时候会返回一个 promise ,使用这个 promise 我们可以取消倒计时。先打开 app.js .. 这里我们可以给 $timeout 返回来的 promise 起个名字,再把它放到 $scope 上面 ... $scope.timer ... 使用它我们就可以取消倒计时 ..

在下面的 gameOver 这个函数里面,使用 $timeout 的 cancel 方法 ... 然后把 $timeout 返回来的 promise 作为这个方法的一个参数 ... 这里就是 $scope 上面的 timer ...

这样执行 gameOver 的时候,会先取消掉倒计时 ... 保存 ... 下面我们在 index.html 上面再去添加一个按钮,让这个按钮可以去执行 gameOver ...

打开 index.html ,在这个 UserController 里面,再用一个 button 标签 ... 按钮上的文字是 取消游戏 ... 加上一个 ng-click ... 点击这个按钮要做的就是去执行 gameOver ...

保存 ... 到浏览器上再去试一下 ... 点击 开始游戏 ... 这样倒计时三秒钟以后,会去执行 gameOver ... 刷新一下这个页面 ... 再点一下这个 开始游戏 ... 接着再点一下 结束游戏 ... 这样会立即执行 gameOver ... 它会先取消 gameOn 里面的倒计时 ... 然后在控制台上输出 游戏结束 ...

来自 https://ninghao.net/video/2063#info


30)$q


Angular 的 $q 这个服务,可以帮助我们在应用里使用异步功能。跟异步对应的就是同步,用一个现实生活的例子来理解一下他们之间的区别。

比如我要通知小雪,中午不回家吃饭了,我可以给小雪打个电话,或者发个短信。打电话就像是同步的功能,拔打小雪的电话,我得一直得到小雪接通了电话,然后告诉她我中午不回家吃饭了,在这个过程中,我不能去做其它的事情。得等着 ...

发短信就像是一个异步功能,我发了个短信,告诉小雪中午不回家吃饭了,然后我就可以去干别的事情了,比如到商场买两包纸尿裤什么的 ... 一会儿小雪收到短信,然后给我回了个信息,我看到了信息,再决定下一步要做的事,比如小雪回复,不行 ... 那我就得回家吃饭,如果回复,ok ... 我就决定继续待在外面。

$q 这个服务用到了 deferred/promise .. 理解什么是 deferred / promise ,我们可以先看一个故事 ... Andy Shora 用卡通的形式解释了什么是 deferred/promise ...

一个关于 promise 的故事:爸爸跟儿子
http://andyshora.com/promises-angularjs-explained-as-cartoon.html

-------

星期天一早,爸爸让儿子帮着上网查查今天的天气,他决定,如果天气好的话,就出去钓鱼,天气不好的话,就待在家里准备晚上烧烤 ... 还有一种可能,就是儿子没法查到天气,家里可能装的是铁通宽带,经常掉线,如果是这样的话,爸爸也决定待在家里 ...

儿子收到了爸爸的请求,答应爸爸会给他带回天气的情况 ... 在儿子查天气这期间,爸爸可以继续去做他的事情 ... 一会儿,儿子如果能兑现他的承诺,带着天气情况回来找爸爸,爸爸就会根据事先规划好的,天气好就去钓鱼,天气不就待在家里 ...

--------

代码

在这个故事里,爸爸就像是一个 Controller 控制器,儿子像是一个 Service 服务 ...

下面我们再看一下这个小故事转换成代码的话大概是什么样子的 ...

这是一个可能包含在控制器里的函数,比如 FartherController ... 爸爸控制器 ... 在这个函数里,用到了一个 SonService ... 儿子服务 ... 用了他的 getWeather() 这个方法去获取天气的情况 ... 然后用了一个 then ... 这个方法有两个参数,第一个是儿子兑现了承诺以后要执行的函数 ... 这个函数上有个叫 data 的参数,儿子如果成功得到了天气情况,这个天气情况就是这里的 data ... 在这个函数里面,判断了天气情况 ... 如果是 good ... 就执行 prepareFishingTrip() 准备去钓鱼 ... 如果是其它的天气情况,就执行 prepareSundayRoastDinner() ... 去准备晚餐 ...

.then 的第二个参数是不能兑现承诺以后要执行的函数 ... 这里也去执行 prepareSundayRoastDinner() ...


image.png

再看一下 SonService ... 儿子服务 ...

image.png

这个服务里面有一个 getWeather 方法 ... 就是 FartherController 用到的这个方法 ... 在这个方法里面,用到了一个叫 $http 的服务 ... 它可以发送 http 请求,这里用的是 $http 的 get 方法 ... 这个方法可以去到指定的地方获取到数据 ...

$http 这个服务用到了 $q 服务 ... 所以它会返回一个 promise ,也就是承诺 ... 接着用了 .then .. 也就是如果上面的 get 方法成功得到了数据,就会去执行这个 then 方法里面的第一个参数的函数 ... 如果出现错误的话 ... 就会执行 .then 里面的第二个参数的函数 ...

成功得到天气情况要做的事这里,判断了一下用 get 方法返回来的数据的 data 属性,如果是 object 的话,就履行承诺,返回响应回来的数据 ...

如果不是,就返回一个 $q.reject ... 意思就是拒绝承诺,这样会去执行 .then 里的第二个参数的函数 .... 同样这个函数里面,也用到了 $q.reject ...

来自  https://ninghao.net/video/2064


31)$q - 提供的东西


我们可以先来看一下 $q 这个服务提供的一些东西。在这个 app.js 里面,定义已经好了一个空白的控制器,UserController,还有一个空白的服务 ... GithubService ,我们假设这个服务提供了一些跟 Github 相关的功能,比如使用 Github 的帐户登录的功能。

myApp.controller('UserController', function () {
});

myApp.factory('GitHubService', function () {
});

在这个服务里面,我们可以先注入 $q 这个服务 ... 另外还有 $log 这个服务 ,它可以在控制台上输出一些东西。在这个服务里定义一个方法,比如叫做 _login ... 然后在返回这个方法,这样我们就可以在别的地方使用服务里定义的这个 _login 方法了。

myApp.factory('GitHubService', function ($q, $log) {
var _login = function () {
};
return {
login: _login
};
});

在这个方法里,先用一下 $q 服务的 defer() 这个方法,去创建一下Deferred 对象 ... 然后在控制台上输出这个对象 ...

var defer = $q.defer();
$log.log(defer);

在看一下 UserController 这个控制器,我们可以在这个控制器里使用 GitHubService 这个服务 ... 把它注入进来 ... 然后可以直接在这个控制器里使用 GitHubService 这个服务里面的 login 方法 ...

myApp.controller('UserController', function ( GitHubService) {
GitHubService.login();
});

这样这个控制器加载以后,就会立即去执行 GitHubService 的 login 方法 ... 也就会在控制台上输出使用 $q 创建的 Deferred 对象了 ...

在 index.html 这个文档里面,我们已经把 UserController 用到了一个 div 元素上面 ... 打开浏览器的控制台 ... 在这里你会看到这个 Deferred 对象 ...

这个对象里面有几个方法,notify ,负责通知异步处理的过程 ... reject,表示拒绝,可以用它来拒绝 promise ,还有 resovle ,用来决定要去做一些事情 ... 另外还有一个 promise 属性 ... 在这个属性里面你会看到 $$state ... 履行或者拒绝 promise 带来的内容会包含在这个属性里面,现在这里还没有什么东西。

这个 promise 属性里面,还有一个 then 这个方法 ... 一会儿我们会用到它来处理履行或者拒绝 promise 之后要做的事情。

来自  https://ninghao.net/video/2065#info



32)使用 promise


Angular 里面有一些服务会自动返回 promise ,不需要我们自己去创建。不过有些时候,你可能想要去整合第三方的一些东西,如果你需要异步处理的功能,就需要自己手工去创建 promise ... 在上一个视频里,我已经创建了一个 Deferred 对象,在这个对象里就包含一个 promise ... 下面,我们看一下怎么去用它。

打开 app.js ,在这个 GitHubService 服务的 _login 方法里面,已经创建好了一个 Deferred 对象 ... 下面,假设我们向 Github 服务器发送了一个 http 的请求,这个请求会给我们返回来一些数据,数据里可能会包含状态的信息,用户在 Github 网站上的用户名等等 ... 这里我们可以虚拟一下,直接创建一个 data 对象,假设这个 data 对象里的内容是 Github 服务器给我们返回来的东西 ...

我们可以根据返回的 data 数据来决定下一步要做什么,可以使用 resolve 带着返回来的数据决定去做一些事情,也可以使用 reject 的方法带着一个错误信息,去处理遇到的问题。

先用一个 if 语句来判断一下 ... 条件是 data 的 status 是不是等于 ok ,如果是 ok,表示我们向 Github 服务器发出的请求得到了回应 ... 这样我们就可以使用 resolve 方法,带着这个返回来的数据去做一些事情 ... defer.resolve(data);

加上一个 else ... 如果 status 不等于 ok ,那可能是遇到问题了,我们就使用 reject ... 带着一个错误信息 ... 去处理遇到的问题。

if (data.status === 'ok') {
defer.resolve(data);
} else {
defer.reject('用户不允许使用 github 帐户');
}

下面,我们要去设计一下,当使用 resolve 决定要做的事,还有处理 reject 发过来的问题。这里我们要用的是 promise 的 then 这个方法 ... 输入 defer.promise ... 使用它的 then 方法,这个方法的第一个参数是一个函数,就是决定要做的事,它的第二个参数是处理遇到的问题的函数 ...

先添加它的第一个参数 ... 用一个匿名函数 ... 可以把 resolve 发过来的数据传递到这里 ... 比如叫它 data ... 在这个函数的里面,我们简单的在控制台上输出点东西 ... $log.info ... 输出 Hello ... 加上 data 里面的 userName 这个属性的值 ...

再去设置一下这个 then 的第二个参数,就是处理遇到的错误 ... 用一个匿名函数 ... 这个函数可以接受用 reject 发过来的东西 ... 这里叫它 error ... 然后在这个函数里面,去到控制台上输出遇到的问题 ...

这个 then 方法是可以链式使用的,也就是,你可以在这个 then 的后面继续去使用 then ...

defer.promise
.then(
function (data) {
$log.info('Hello ' + data.userName);
},
function (error) {
$log.warn(error);
}
);

保存 ... 在控制台上,你会看到 Hello ninghao ... 执行了 promise 的 then 里面的第一个参数里定义的动作 ... 因为我们决定当请求 GitHub 服务器的时候,如果返回来的数据里面,status 的值是 ok 的话,就会决定用这个返回来的数据去做一些事情。 这样也就会去执行 promise 的 then 里面的第一个参数里设计的动作。

下面, 我们把这个 data 里的 status 的值改成 not ok ... 再保存一下 ... 这样就会用 reject 发出一个错误 ... 也就会用到 promise 的 then 里面的第二个参数里设计的动作,在控制台上输出这个发过来的错误信息。


来自  https://ninghao.net/video/2066#info

33)$http


$http 这个服务就是在 Angular 上使用 Ajax 功能的方法。使用这个服务提供的功能,我们可以向服务端发出 http 的请求, 比如去获取一些信息,或者发送一些信息给服务端。

在 app.js 这个文件里面,现在有一个空白的控制器,叫 ShowController ... 下面,为了简单的演示一下 ... 我们可以直接在这个控制器上去使用 $http 这个服务 ... 如果你觉得是可以重复使用的功能,可以把它们定义成一个服务,然后再注入到这个控制器里来用。

先把 $http 注入到这个控制器上 ... 另外还有 $scope

myApp.controller('ShowController', function ($http, $scope) {
});

然后在这个控制器里,可以先在 $scope 上面,定义一个方法 ... 这个方法可以叫做 getShows ... 用这个方法去获取到电视剧的内容。

$scope.getShows = function () {};

在这个方法里,我们可以使用 $http 的 get 这个方法,去到服务器得到一些东西 ... 在 app 这个目录的下面,我手工的创建一个 json 格式的文件 ... 就是这个 data.json ... 一般这个数据是服务端动态提供的,不过为了演示,我们可以用 $http 的 get 方法,直接去请求这个 data.json ...

把这个请求的地址交给 get 方法 ... 因为 $http 这个服务用到了 $q 服务,所以它会返回一个 promise ... 这样我们就可以使用 promise 的 then 方法,去处理成功获取到数据以后要做的事,还有出现错误的时候要做的事 ..

使用 then 的好处就是,我们可以在这个 then 的后面继续去使用 then ... then 字面上的意思就是然后,然后怎么样 ... 比如你可能需要先用 get 得到一些数据,然后根据这些数据继续去做处理 ...

我们可以先去设计一下这个 then 里面,决定要做的事情,也就是获取数据成功以后要做的事情 ... 用一个匿名函数作为它的第一个参数 ... 这个函数支持一个参数,可以叫它 data ... 发出的请求,返回来的东西,会包含在这里面。

这个函数要做的事就是,把得到的数据放到 $scope 上面,这样我们就可以在视图上面,去使用服务端返回来的这些数据了 ... $scope.shows 等于 data.data .. 因为返回来的数据里面,会包含数据本身,状态,页头信息等等,真正的数据包含在 data 这个属性里面。

接着再去设计一下 then 的第二个参数,就是失败的时候要干的事儿 .. 同样是一个函数 ... 它也可以接受一个参数 ... 这里可以叫它 error ... 请求出现错误,我们就在控制台上输出错误的信息 ... 用一个 $log.log ... 输出 error 里面的 data 这个属性里的值,也就是直接输出错误的具体的信息。这里想要使用 $log ,你需要把它作为这个控制器的一个依赖注入进来 ...

保存 ... 再回到 index.html ... 我们先在一个元素上使用 ShowController 这个控制器 ... 然后再添加一个按钮 ... 按钮上的文字是 显示 ... 上面加上一个 ng-click .. 点击这个按钮,就去执行 getShows 这个方法 ...

在它的下面,再用一个 ng-repeat ,去循环的输出获取到的电视剧的列表 ... 先用一个 ul 标签 ... 然后要循环的是 li 标签 ... 在上面用一个 ng-repeat ... show in shows ... 在输出的内容是 title 这个属性里的东西 ...

保存 ... 打开浏览器 ... 在页面上会有一个 显示 的按钮 ... 点一下这个按钮 ... 这样会去执行 ShowController 里面的 getShows 这个方法,在这个方法里面,我们用到了 $http 服务的 get 方法,到指定的地方去请求一些数据,然后我们把这些数据交给了 $scope 上面的 shows 里面。 得到这个数据以后,在 index.html 里面,使用 ng-repeat 循环的输出电视剧的标题 ...

来自 https://ninghao.net/video/2067#info

附录

34)Controller as 语法


在这个课程里我们在把控制器里的数据传递给视图的时候,都是通过 $scope 这个中介,先把 $scope 作为依赖注入到控制器里,然后再把数据作为它的一些属性。在 AngularJS 1.2 以后的版本里,我们可以使用一种叫 controller as 的语法 ...

下面使用这种用法去改造一下这个控制器 ... 首先可以去掉依赖的这个 $scope ... 为视图提供的数据可以放到 this 上面 ... this 表示当前控制器的实例 ...

回到 index.html ... 在视图上使用控制器也需要调整一下 ... 在这个 div 上面用到了 UserController 控制器 ... 这里需要在它后面加上一个 as 然后再给这个控制器的实例起个名字 ... 比如叫它 user ...

在绑定数据的地方,我们可以用到这个名字 ... 比如这个 userName ... 在它前面要加上 user. 保存 ... 在浏览器上会正常的显示出 userName 里面的值 ...

回到 app.js ... 在使用 Controller as 语法的时候,可以所数据放到 this 上面 ... 不过一般,我们可以把这个 this 再起个其它的名字 ... 通常我们可以叫它 self ... 这是因为 JavaScript 本身的原因,这样做会更好一点...

var self = this;

来自 https://ninghao.net/video/2068#info


35)安全的依赖注入的方法


在 Angular 里面使用 Dependency Injection ,也就是依赖注入,比如这里我们把 $log 这个服务注入到了 UserController 这个控制器里,然后在这个控制器里使用了这个服务提供的功能,就是在控制台上输出了一个 hello ...

这段代码在最小化以后,会有一些变化.. 我们可以先看一下 ... 打开命令行工具 ... 输入 gulp scripts ... 这个任务是我事先设计好的,它可以把 app.js 这个文件最小化,然后重命名为 app.min.js ,放到 app 下面的 js 这个目录里面 ... 打开这个文件看一下 ...

image.png

这里你会发现,我们作为依赖注入到这个控制器里的 $log 服务的名字,变成了简写的 l ... 这样在控制器里使用这个 l 上面的方法,Angular 是不认识的 ... 会出现错误的提示 ...

image.png

解决这个问题的方法就是使用安全的依赖注入的方法 ... 先回到 app.js ... 我们可以把这个控制器的第二个参数,放到一个数组里面 ... 然后在这个数组的一开始的项目,可以放一些要注入的依赖 ... 这里就是 $log ... 注意要在它的周围加上引号 ... 逗号分隔一下 ... 这样它会作为最后的这个 function 的参数的名字传递过来 ... 也就是,不管我们把 function 里面的 $log 换成什么,都可以正确的使用 $log 这个服务提供的方法 ...

这里要注意一下顺序,比如还有其它的要注入的东西,数组里的项目的顺序,要跟 function 里面的参数的顺序是对应的 ... 名字不重要,但是顺序很重要 ...

回到命令行,再执行一下 gulp scripts ... 

image.png

打开 app.min.js ... 最小化以后,虽然 function 里面的 $log 也会变成简写的 l ... 不过前面我们有一个 $log 作保证,所以,在这个函数里,可以正常的使用注入进来的服务上面的方法 ...

image.png


来自 https://ninghao.net/video/2069#info



普通分类: