用Angular打破旧世界

2014年11月某日,我接到一个任务,给公司ERP系统的创建订单功能做一些增强,支持海外下单和搜索提示。
现状:目前的创建订单功能都是基于城市这个唯一维度来做的,页面加载的是百度地图。
应用场景:用户在国内提前下单,在国外使用。
初期需求:在创建订单过程中根据用户所选择的城市来加载百度或谷歌地图,
选择国外城市后,搜索地址要能拿到对应的poi,系统能成功创建订单。
分析:谷歌地图服务在国内基本处于不可用的状态,地图加载非常缓慢,最重要的是搜索地址无法拿到poi。
讨论:经过和系统组老大、pm讨论,决定把此问题一分为二,那就是地图加载不了,拿到数据就行。
最终需求:地图可以不加载,但搜索一定要能拿到poi。
解决方案:租赁一台VPS做中间请求转发,绕过国内无法直接访问谷歌的限制。
估算工期:我心想方案已经确定,而且接口有现成的,应该不太难,所以我估计了五天。
我先做了个简单的demo,利用极路由自动翻墙的特性,成功加载谷歌地图,搜索地址成功拿到poi。
当我考虑如何把我的代码融入现有的代码中时,我傻了眼,现有的代码完全无法阅读。
html页面上各种php语句和变量,随便一个js文件代码几千行,
几乎没有注释,函数的层层调用,让你完全理不清这业务逻辑。
我看了半天后,头都大了,一瞬间我有种想重构整个代码的冲动。
为什么我想重构?
因为每次当我打开那个文件,看到满屏的代码,滚动条怎么下拉也看不到尽头的时候,人都绝望了。
与其在这个旧世界中干着一些敲敲打打,修修补补的工作。
不如用锤子砸开这个旧世界,迎来一个新世界。
而这个锤子就是angular.js。
说干就干。
这个功能中的数据(Data)来自两部分:
1、php语句在后端直接生存(譬如城市列表):

$city=json_encode($cityList->get(cityId))

2、通过ajax访问后端接口返回(譬如机场数据集合):

$http.post(url,{data}).success(function(res){})

我找来后端工程师,咨询了下后端直接生存数据的部分,然后用js中的变量来引入。

var city = <?=$city=?>;

无论是通过本地还是ajax拿到的数据,都是一样的json格式。
然后我开始构建页面,使用ng-repeat指令循环数据生成页面。
整个生成页面的过程无比顺畅,比之前jQuery的做法(在js中构建一个html模版,然后用数据来填充,最后循环插入)不知道简单多少倍。
这也是当初最吸引我使用angular.js的原因,代码量大量减少,整个页面看起来赏心悦目多了。
没有事情是一帆风顺的,在引入angular到现有项目的过程中也遇到了两个问题。

如何做到选择下拉列表后,后面的起点或终点机场数据自动更新?

之前的做法是监控select的change事件,在回调函数中手动操作数据更新。
过程非常繁琐,为什么呢?
因为我们首先要知道用户到底选择了哪个机场,然后把这个机场对应的id传输给前面的机场数据集合,
然后根据id找到对应的机场数据,最后把拿到的机场数据操作dom,更新视图。
这中间涉及到:取值-转化-传值-求值-dom操作。
就是一个这么简单的需求,如果用传统的做法来实现,要写一百多行。
但用angular.js来实现,三行代码足矣。

$scope.$watch('airpotModel',function(){
$scope.$apply(); //触发脏检查
})

这是我当时的写法,随着后来对angular的深入了解,发现ng-option指令,
解决方法更简单了,详情查看我下篇文章。

如何控制引入angular带来的边际成本?

控制angular的应用范围是最重要的部分,在这一点上我也是走了很多弯路,与大家分享。
千万别尝试在一个现有项目中改造一个页面所有的部分来适应angular,
而是只在核心部分使用angular,然后用ng-app来控制angular的应用范围,
这是成本最低的解决方案,也是我血一般的经验教训。