本节我们会通过构建一个简单的笔记存储应用(可以载入并修改一组简单的笔记)来学习如何应用Angular的特性。这个应用用到的特性有:

  1. 在JSON文件中存储笔记
  2. 展示、创建、修改和删除笔记
  3. 在笔记中使用Markdown格式
  4. 同步编辑和预览Markdown

  本应用已经包含了基础的HTML和CSS代码,还有一个用Node写的简单的RESTful服务器,用于管理笔记,这样我们就可以专注于Angular而不是API。我们学习的重点是如何把Angular加入其中并学习它的重要特性。

  3.2.1 获取项目文件

  首先,我们需要来获取一下该项目的文件,可以通过git来获取,执行如下命令:

    $ git clone https://github.com/ionic-in-action/chapter3.git(克隆chapter3仓库)

    $ cd chapter3(切换到chapter3目录)

    $ git checkout step1(检出step1标签)

  (如果你不想使用git,可以直接下载文件:https://github.com/ionic-in-action/chapter3/archive/step1.zip)

  3.2.2 启动开发服务器

  由于这个项目搭载的是RESTful服务器,需要你掌握一些NodeJS的知识。在项目server.js文件中可以看到一个简单的RESTful服务器,它是基于Express.js框架开发的,这样做的原因是你需要长期管理笔记,通过RESTful API可以让应用阅读、创建、编辑和删除列表中的笔记。服务器还可以通过HTTP请求把文件载入浏览器,ionic serve就是通过这种方式来运行你的Ionic应用的。

  需要注意的是:

  • 服务器运行在3000端口上;
  • 服务器会接受请求,根据URL和HTTP方法来修改列表中的笔记;
  • 服务器使用JSON文件来作为数据库(data/notes.json),你可以根据自己的情况使用其他的数据库;

  如果服务器不能运行,则说明你缺少一些必备的node包,解决方法,在终端中进入项目目录,运行$ npm install,npm会检查依赖列表并下载依赖。

  然后输入命令$ node server来启动服务器,如果需要终止服务器可以按Ctrl+S或者直接关闭命令窗口。

  运行后的基础模板如下图所示:

  

  3.2.3 创建Angular应用

  Angular开发简单来说就是用JavaScript创建一个Angular应用并在HTML中使用它。Angular和DOM紧密结合,所以你可以把一个Angular应用严格限制在一个DOM元素及其子元素中。在本例中使用的是<html>元素,所有Angular可以访问整个页面。Ionic通常使用的是<body>元素。

  首先,你必须要先载入Angular库,然后要创建一个Angular应用,你需要在一个元素上使用ngApp指令并声明应用名称。打开index.html文件,并添加ngApp指令:

<html lang="en" ng-app="App">

  现在,你已经把一个名为App的Angular应用附加到了HTML根元素上。这样Angular就可以访问整个DOM,不过你也可以把它附加到<body>标签中。我们建议把它放在<html>或者<body>元素中。

  上面我们只是添加了ngApp的指令,还没有在JavaScript中声明这个应用,下面我们来完成这一步。Angular有一套模板系统,用来封装程序代码。声明新模块时,你需要提供名字和一个数组,其中包含所有依赖。Ionic本身也是一个Angular模块。Angular模块的声明方式如下,创建一个新文件js/app.js并写入下面的代码:

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

  最后,在index.html文件</body>标签前添加一个<script>标签来载入Angular模块:

<script src="js/app.js"></script>

  你现在已经在页面中声明并载入了一个最基本的Angular应用。angular.module()方法会创建模块并把它附加到ngApp所属的DOM元素中。这是最基本的Angular应用,实际上它现在没有任何功能。所有的Angular应用都是用这样的方式定义的。

  3.2.4 添加控制器

  控制器:控制数据和业务逻辑

  我们需要添加一个控制器来控制应用中多个部分的业务逻辑,它不会改变浏览器中应用的样子,因为控制器只负责管理数据,不影响应用的视觉效果,不过我们需要在管理视觉元素之前搞定控制器。添加控制器之后,它就可以访问页面中的某个特定区域。

  下面我们来声明一个简单的控制器。首先你需要引用App模块并使用控制器方法来声明一个控制器。需要传入控制器的名字以及一个包含控制器逻辑的函数。创建文件js/editor.js:  

//编辑控制器 js/editor.js
angular.module('App') //引入App模块并把它引入这个控制器中
.controller('EditorController',function($scope){ //声明EditorController控制器,传入一个包含依赖列表的函数
$scope.state={ //创建模型的值并存储到$scope中
editing:false
};
});

  这个控制器现在非常简单,只是创建了一个简单的模型state。$scope服务被注入,所以你可以设置它的属性。记住,$scope中的值被称为模型,可以在视图中访问。

  现在修改index.html文件,把控制器加入应用中,在</body>前引入editor.js文件:

<script src="js/editor.js"></script>

  最后将控制器附加到DOM中。这会给控制器创建一个新的子作用域。我们需要用一条Angular指令来盛勇控制器被附加的位置:

<div class="container" ng-controller="EditorController">

  注:$开头的服务

  Angular中的服务以$符号开头,Ionic的服务也是如此。以$开头的服务,按惯例是Angular核心服务或者Ionic服务。

  3.2.5 加载数据并将数据显示在应用中

  加载数据:使用控制器来加载数据并显示在视图中

  下面我们来加载数据并把它显示到应用中,在应用的基础模板左侧已经有一个创建好的空的笔记列表。然后我们加入一些简单的笔记,更新控制器从而把数据载入应用。要实现这个功能,需要使用Angular的$http服务,通过$http服务来请求Node服务器的数据。我们来具体操作一下:

  先修改控制器,通过HTTP请求访问服务器的笔记服务并把返回的数据赋值给作用域。打开js/editor.js文件,更新代码:

angular.module('App')
.controller('EditorController', function ($scope,$http) { //把$http服务注入控制器
$scope.editing = true; $http.get('/notes').success(function(data){ //使用$http.get加载笔记,如果成功,使用法内的数据
$scope.notes = data; //把从http返回的数据赋值给$scope
}).error(function(err){ //处理错误,存储错误
$scope.error = 'Could not load notes';
});
});

  注意控制器函数中可以给函数声明任意数量的参数,Angular会通过名字来定位服务并注入控制器。上面代码中$http的使用方法叫做依赖注入(DI),是Angular一个非常强大的特性,可以让你的控制器使用各种服务。由于Angular的服务并不是全局的,所以必须先注入再使用。

  这时我们启动服务,但是在页面上看不到任何数据,而我们访问http://localhost:3000/notes,发现json数据可以访问没有问题,那是为什么我们看不到数据呢?因为我们需要更新index.html模板文件,用Angular指令把数据从$scope中显示出来,对index.html文件,我们需要进行如下修改:

<div class="col-sm-3">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><button class="btn btn-primary btn-xs pull-right">New</button> My Notes</h3>
</div>
<div class="panel-body">
<!-- ngIf会根据是否有笔记来判读是否把这个元素插入DOM -->
<p ng-if="!notes.length">No notes</p>
<ul class="list-group">
<!-- ngRepeat会循环每个笔记并显示笔记标题 -->
<li class="list-group-item" ng-repeat="note in notes">{{note.title}}><br />
<!-- 绑定显示日期,使用过滤器显示较短的日期 -->
<small>{{note.date | date:'short'}}</small></li>
</ul>
</div>
</div>
</div>

  说明:模板中{{note.date | date:'short'}}有个| date:'short',这是一个过滤器,它会在不改动作用域值的前提下修改显示内容。在表达式中可以通过管道符来使用过滤器,过滤器可以串联,也就是说可以添加多个过滤器。

  加载数据后的笔记截图:

   

  3.2.6 处理选择笔记的单击事件

  如果需要单独查看某条笔记,需要单击左侧列表笔记时,将他们显示在右侧。

  使用ngClick可处理用户的单击事件,然后把笔记数据赋值给一个新的模型,用来进行显示,我们来打开模版index.html,修改笔记列表的部分,添加单击事件处理器:

<ul class="list-group">
<!-- ngRepeat会循环每个笔记并显示笔记标题;ngClick会调用view()并传入下标;添加ngClass,如果笔记被选中就添加active类 -->
<li class="list-group-item" ng-repeat="note in notes" ng-click="view($index)" ng-class="{active: note.id == content.id}">{{note.title}}><br />
<!-- 绑定显示日期,使用过滤器显示较短的日期 -->
<small>{{note.date | date:'short'}}</small></li>
</ul>

  当单击笔记时,Angular会尝试调用$scope.view()函数,ngClass指令可以根据情况向元素添加css类。$index值时ngRepeat提供的特殊变量,被传入视图函数里,作用就是告诉你当前被使用的数组元素的下标,此处指的是被单击元素的下标。

  下面我们来创建视图函数,打开editor.js文件,在控制器函数里添加视图函数:

$scope.view = function(index){        //声明一个名为view的新$scope方法,接受被点击元素的下标
$scope.editing = false; //把editing状态设置为false,因为此时用户要查看元素
$scope.content = $scope.notes[index]; //给content模型设置一个新模型,包含被单击的笔记
};

  此时,当我们点击笔记时,click时间会触发控制器中view()方法,它会根据传入的下标值找到被点击的笔记,并将笔记内容赋值给新的content模型,同时,editing模型也会被设置为false。

  3.2.7 更新模版显示被选择的笔记

  此时点击笔记,右侧面板不会有变化,因为我们还没有修改右侧显示的面板,右侧面板有两种状态,一个是展示笔记,一个是编辑笔记,$scope.editing属性将决定显示哪个面板。再次打开index.html文件作如下修改:

<!-- ngHide会在本条件为真时隐藏头部,在这里editing为true的时候条件为真 -->
<div class="panel panel-default" ng-hide="editing">
<div class="panel-heading">
<!-- 把title绑定到头部 -->
<h3 class="panel-title">{{content.title}} <button class="btn btn-primary btn-xs pull-right">Edit</button></h3>
</div>
<!-- 把content绑定到正文 -->
<div class="panel-body">{{content.content}}</div>
<!-- 绑定笔记日期并把它传递给过滤器 -->
<div class="panel-footer">{{content.date | date:'short'}}</div>
</div>
<!-- ngShow会在条件为假时隐藏底部,在这里editing为false的时候条件为假 -->
<form name="editor" class="panel panel-default" ng-show="editing">

  再次运行应用,此时单击笔记即可实现查看功能,如下图所示:

  

  3.2.8 创建指令,解析Markdown格式的笔记

  要实现把Markdown格式的文本转换为HTML,需要使用Showdown这个js库。

  打开app.js文件,指令不是控制器的一部分,所以代码需要被存储到应用主文件中,具体代码如下:

//声明命令并命名为markdown
.directive('markdown',function(){
//创建showdown转换器,下面会用到
var converter = new Showdown.converter();
//命令会返回一个对象,用来声明命令的设置
return {
//声明自定义作用于,等待值被赋给markdown属性
scope:{
markdown:'@'
},
//声明link函数,它会把markdown转换成html
link:function(scope,element,attrs){
//使用作用于观察器来同步模型改动
scope.$watch('markdown',function(){
//把markdown转换成html并存入content变量
var content = converter.makeHtml(attrs.markdown);
//把转换好的html内容注入到元素内
element.html(content);
});
}
}
});

  现在我们打开index.html文件,传入markdown内容:

<div class="panel-body" markdown="{{content.content}}"></div>

  改为markdown笔记格式的页面效果如下:

  

  笔记展示功能已完成,下一节来实现编辑功能。

  

3.2 配置构建Angular应用——简单的笔记存储应用的更多相关文章

  1. 3.2.1 配置构建Angular应用——简单的笔记存储应用——展示功能

    本节我们会通过构建一个简单的笔记存储应用(可以载入并修改一组简单的笔记)来学习如何应用Angular的特性.这个应用用到的特性有: 在JSON文件中存储笔记 展示.创建.修改和删除笔记 在笔记中使用M ...

  2. 3.2.1 配置构建Angular应用——简单的笔记存储应用——编辑功能

    本节我们会接着上节课的内容,继续来完成使用Angular来创建简单的笔记存储应用,上一节课,我们完成了笔记的展示功能,本节课,我们来完成编辑功能. 编辑主要是两个功能:编辑现有的笔记以及创建新笔记.首 ...

  3. android studio+grade配置构建

    Android 构建系统编译应用资源和源代码,然后将它们打包成可供您测试.部署.签署和分发的 APK.android Studio 使用 Gradle 这一高级构建工具包来自动化执行和管理构建流程,同 ...

  4. jenkins配置构建执行状态

    运行构建 在项目 左侧列表点击 “立即构建” ,在 “Build History” 列表中,会看到执行状态,蓝色圆点表示构建成功,红色圆点表示构建失败 点击 构建失败的任务(红色的小圆点).然后点击“ ...

  5. C# 构建XML(简单示例)

    C# 构建XML的简单示例: var pars = new Dictionary<string, string> { {"url","https://www. ...

  6. Redis:安装、配置、操作和简单代码实例(C语言Client端)

    Redis:安装.配置.操作和简单代码实例(C语言Client端) - hj19870806的专栏 - 博客频道 - CSDN.NET Redis:安装.配置.操作和简单代码实例(C语言Client端 ...

  7. win2008系统:iis配置备份和还原简单操作

    (2013-09-26 16:33:22) 转载▼   分类: 开发类 当我们电脑系统有大量的站点和虚拟目录的时候,电脑因为种种原因需要重做系统,那么重装系统后这些站点我们是否只能一个一个的添加,如果 ...

  8. Ubuntu下配置python完成爬虫任务(笔记一)

    Ubuntu下配置python完成爬虫任务(笔记一) 目标: 作为一个.NET汪,是时候去学习一下Linux下的操作了.为此选择了python来边学习Linux,边学python,熟能生巧嘛. 前期目 ...

  9. Log4j简单学习笔记

    log4j结构图: 结构图展现出了log4j的主结构.logger:表示记录器,即数据来源:appender:输出源,即输出方式(如:控制台.文件...)layout:输出布局 Logger机滤器:常 ...

随机推荐

  1. Netty 系列之 Netty 高性能之道

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用 Netty4 + Thrift 压缩二进制编解码技术,他们实现了 10 W TPS(1 K 的复杂 POJO 对象)的跨 ...

  2. php实现数据粘性例子

    php实现数据粘性例子 在填表单的时候,有时候会出现表单未填完就提交的情况,这时候若是想要回到原来的表单页面,一般之前填的内容都会消失掉. 故使用PHP实现回到原来表单但是填写数据不消失,代码

  3. 在UP Board 上搭建M——L服务器

    前言 原创文章,转载引用务必注明链接,水平有限,欢迎指正. 本文环境:ubilinux 3.0 on UP Board 初识免流 所谓免流,就是免除手机访问网络产生的流量费用.其原理在乌云网上有过报道 ...

  4. Redis常用命令(String数据类型)

    一.概述:      字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等.在Redis中 ...

  5. PowerDesigner连接Oracle并导出表结构

    环境:Oracle 11G(远程) + win32_11gR2_client + PowerDesigner 15 一.下载.安装.配置 1.下载地址 win32_11gR2_client客户端下载地 ...

  6. java创建文件和目录

    java创建文件和目录 2013-09-04 12:56 99933人阅读 评论(7) 收藏 举报  分类: JAVA基础(10)  版权声明:本文为博主原创文章,未经博主允许不得转载. 创建文件和目 ...

  7. 如何保存gnome的linux的 会话?相当于windows下的休眠?

    在关机前, 你进行的所有操作, 的集合, 就叫做你跟 linux系统 机器间的 一次 会话, 一个session. linux 可以 在关机时保存 这些session, 保存这些打开的窗口 和程序. ...

  8. BFC

    先看一下英文解释:Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cell ...

  9. [Algorithm] 群体智能优化算法之粒子群优化算法

    同进化算法(见博客<[Evolutionary Algorithm] 进化算法简介>,进化算法是受生物进化机制启发而产生的一系列算法)和人工神经网络算法(Neural Networks,简 ...

  10. C# socket send方法

    转  http://msdn.microsoft.com/zh-cn/library/d318fkch(v=vs.80).aspx