【Ionic+AngularJS 开发】之『个人日常管理』App(二)
准备工作
资源
预装工具
安装bower
npm install -g bower
bower install ngCordova
(*由于网络获取资源的原因,后面几次建项目后都无法下载到,自己便复制了原来的ngCordova目录(到YourProject\wwww\lib目录下),发现也是可以使用的)
下载好后,在项目的index.hmtl进行引用:
<script src="lib/ngCordova/dist/ng-cordova.js">
日历工具
安装插件
本项目需要(安装)的插件有:
| 插件名 | 说明 | 扩展阅读 | 
|---|---|---|
| cordova-plugin-x-toast | 消息提示,使用方法如:$cordovaToast.showShortBottom('屏幕下方提示'); (*仅限平台运行,浏览器调试无效,所以在PC调试时应注意其引起的错误而导致后面代码没执行) | cordova ionic消息提示 | 
| cordova-sqlite-storage | sqlite数据库 | cordova调用本地SQLite数据库的方法 more... | 
| cordova-plugin-x-socialsharing | 内容分享 | 
插件的安装基本命令是:
cordova plugin add XXXX
安装好后可在YourProject\wwww\lib目录下看到新增的插件目录,这样就可以在项目中引用了(不用使用<script src="xxx">)。
    在生成platform后,或需再用
cordova prepare
该命令用以复制文件到平台(并更改一些xml文件的内容)
概念理解
service服务
AngularJS服务是一种单例对象,其主要功能是为实现应用的功能提供数据和对象,通过直接调用服务,可以将复杂的应用功能进行简化或分块化。 按功能的不同,分为内置服务和自定义服务。
AngularJS提供的常用内置服务有:$scope、$http、$window、$location等
自定义服务主要包含以下两种:
    1)使用内置的$provide服务
    2)调用模块中的服务注册(如factory、service、constant、value等方法)
本项目主要采用service来创建服务(service方法与factory不同的是,它可以接收一个构造函数)
设计与开发
app.js
 angular.module('pdm'
     , ['ionic'
         , 'ngCordova'
     ])
     .config(function ($stateProvider, $urlRouterProvider, $ionicConfigProvider) {
         //在android下,tab位置为top,如果想修改其位置在底部,加上下面一句代码:
         $ionicConfigProvider.tabs.position('bottom');
         //...
     })
     .run(function ($ionicPlatform) {
         //...
     })
     // 自定义服务:$alertPopup
     .service('$alertPopup',
     ['$ionicPopup'
         , function ($ionicPopup) {
         return function (content, title) {
             if (title == undefined || title == null)title = '提示';
             var alertPopup = $ionicPopup.alert({
                 title: title,
                 template: content
             });
             alertPopup.then(function (res) {
                 log('alertPopup.then: ' + res);
             });
         }
     }])
     // 自定义服务:$db
     .service('$db', ['$cordovaSQLite', '$alertPopup', '$cordovaToast'
         , function ($cordovaSQLite, $alertPopup, $cordovaToast) {
             // 初始化数据表
             var db = null;
             try {
                 var _dbName = 'sk';
                 if (!(window.cordova && window.SQLitePlugin)) {
                     // 创建数据库对象
                     db = window.openDatabase(_dbName, '1.0', _dbName, 100 * 1024 * 1024);
                     // web-sql 执行sql方式
                     // 首次创建记账表
                     db.transaction(
                         function (transaction) {
                             transaction.executeSql("CREATE TABLE IF NOT EXISTS Finacial_KeepAccount " +
                                 "( id integer primary key" +
                                 ", account text " +
                                 ", SuitType text " +
                                 ", ItemText text " +
                                 ", MoneyFlowDirect text " +
                                 ", Cash REAL " +
                                 ", AccountType text " +
                                 ", RecordDate text " +
                                 ", Remark text" +
                                 ")");
                         }
                     );
                     // 自定义执行sql方式
                     // 首次创建日常表
                     $cordovaSQLite.execute(db, 'CREATE TABLE IF NOT EXISTS Life_DailyActivity(id integer primary key' +
                         ', account text' +
                         ', Date text' +
                         ', Business text' +
                         ', Study text' +
                         ', Health text' +
                         ', Sport text' +
                         ', Others text' +
                         ', Remark text' +
                         ')');
                 }
                 else {
                     $alertPopup('fail create ' + _dbName + '.db');
                 }
             } catch (e) {
                 $alertPopup('fail init: ' + e.toString(), '$db Err');
             }
             // 内部函数
             function db_exec(sql, param, succ_callback, err_callback){
                 if (param == undefined || param == null) param = [];
                 $cordovaSQLite.execute(db, sql, param)
                     .then(function (rst) {
                         if (succ_callback == undefined)log('exec: ' + sql);
                         else succ_callback(rst);
                     }, function (err) {
                         if (err_callback == undefined)$alertPopup('exec error: ' + err.message);
                         else err_callback(err);
                     });
             }
             // 外部可调用接口
             return {
                 // 执行sql
                 _exec: function (sql, param, succ_callback, err_callback) {
                     db_exec(sql, param, succ_callback, err_callback);
                 },
                 // 获取数据
                 get: function (tbl, cndt, callback) {
                     var sql = 'SELECT * FROM ' + tbl + ' WHERE 1=1 ';
                     if (cndt != undefined && cndt != '')sql += (' AND ' + cndt);
                     db_exec(sql, [],
                         function (rst) {
                             var data = [];
                             for (var i = 0; i < rst.rows.length; i++) data.push(rst.rows.item(i));
                             callback(data);
                         });
                 },
                 // 添加
                 add: function (tbl, fields, valueArr, silenceExec) {
                     var _param = '';
                     for (var i = 0; i < fields.split(',').length; i++)_param += ',?';
                     _param = _param.substr(1);
                     var sql = 'INSERT INTO ' + tbl + '(' + fields + ') values(' + _param + ')';
                     db_exec(sql, valueArr,
                         function (rst) {
                             if (silenceExec == undefined || silenceExec != true)
                                 if(!g_debug)
                                 $cordovaToast.showShortCenter('add to ' + tbl + ' success');
                         });
                 },
                 // 更新
                 update: function (tbl, fields, valueArr, cndt, silenceExec) {
                     var fv = '';
                     var flds = fields.split(',');
                     for (var i = 0; i < flds.length; i++) fv += (', ' + flds[i] + '=? ');
                     fv = fv.substr(1);
                     var sql = 'UPDATE ' + tbl + ' SET ' + fv + ' WHERE ' + cndt;
                     db_exec(sql, valueArr,
                         function (rst) {
                             if (silenceExec == undefined || silenceExec != true)
                                 if(!g_debug)
                                 $cordovaToast.showShortCenter('update ' + tbl + ' success');
                         });
                 },
                 // 删除
                 delete: function (tbl, cndt, silenceExec) {
                     var sql = 'DELETE FROM ' + tbl + ' WHERE ' + cndt;
                     db_exec(sql, [],
                         function (rst) {
                             if (silenceExec == undefined || silenceExec != true)
                                 if(!g_debug)
                                 $cordovaToast.showShortCenter('delete from ' + tbl + ' success');
                         });
                 }
             }
         }])
 ;
自定义服务:$alertPopup
为方便项目内调用,对$ionicPopup进行封装,也方便日后扩展。
自定义服务:$db
此$db服务基本就是一个DAL层了,封装了基本的CRUD功能,并根据项目需要做了一些“默认处理”(在程序初始化时,自动创建记账和日常表等)。 
    (*这个sqlite文件物理路径很难找,有什么方法可以快速定位,还望知道的园友赐教:))
记账视图
HTML部分
<ion-view view-title="DailyKeeper">
<ion-nav-title><b>记账</b></ion-nav-title>
<div class="bar bar-subheader bar-dark">
<h2 class="title">
<a class="button button-icon icon ion-plus-circled" ng-click="showDetail()"></a>
</h2>
</div> <ion-content class="has-tabs has-subheader">
<ion-list>
<div ng-repeat="da in dailyAccount">
<div class="item item-divider" style="display: {{da.ext_displayDivider}}">
{{da.RecordDate}}
</div>
<ion-item class="item-remove-animate item-icon-right"
type="item-text-wrap" ng-click="showDetail({{da}})" style="color: {{da.ext_TextColor}}">
【{{da.SuitType}}】{{da.ItemText}}
<br/>{{da.Cash}}
<i class="icon ion-chevron-right icon-accessory"></i> <ion-option-button class="button-assertive" ng-click="remove(da)">
Delete
</ion-option-button>
</ion-item>
</div>
</ion-list>
</ion-content> <!--弹出内容-->
<script id="detail.html" type="text/ng-template">
<ion-modal-view>
<ion-header-bar>
<h1 class="title">{{currDA.title}}</h1>
<button class="button" ng-click="closeDetail()">关闭</button>
</ion-header-bar>
<ion-content>
<div class="item-input-inset">
<i class="icon ion-android-calendar"></i> 
<input type="date" ng-model="currDA.RecordDate">
</div>
<div class="item item-input-inset">
<select
ng-model="currDA.SuitType"
ng-options="value.SuitType as value.SuitType group by value.MainClass for value in Finacial_SuitClass">
<option value=""> -账目类型- </option>
</select> 
<label class="item-input-wrapper">
<input type="text" ng-model="currDA.ItemText" placeholder="消费项">
</label>
</div>
<div class="item item-input-inset">
<label class="item-input-wrapper">
<input type="number" ng-model="currDA.Cash" placeholder="金额">
</label> 
<label class="toggle">
<input type="checkbox" ng-model="currDA.Income">
<div class="track">
<div class="handle"></div>
</div>
</label>(入账)
</div>
<div class="item item-input-inset">
<textarea style="width: 100%" ng-model="currDA.Remark" placeholder="备注"></textarea>
</div>
<div class="item-input-inset">
<button class="button button-block button-positive" ng-click="save()">
Save
</button>
</div>
</ion-content>
</ion-modal-view>
</script>
</ion-view>
JavaScript部分
 angular.module('pdm')
     .controller('Ctrl_DailyKeeper',
     ['$scope', '$ionicModal', '$db', '$cordovaToast', '$ionicPopup', '$alertPopup'
         , function ($scope, $ionicModal, $db, $cordovaToast, $ionicPopup, $alertPopup) {
         // BLL
         $scope.getKA = function (callback, cndt) {
             var sql = "SELECT * FROM Finacial_KeepAccount WHERE 1=1 ";
             if (cndt != undefined && cndt != '')sql += (' AND ' + cndt);
             sql += ' ORDER BY RecordDate desc';
             $db._exec(sql, [], function (rst) {
                 if (rst.rows.length == 0) {
                     if(!g_debug)
                     $cordovaToast.showShortCenter('load ka success but no data');
                     //return;
                 }
                 var data = [];
                 for (var i = 0; i < rst.rows.length; i++) data.push(rst.rows.item(i));
                 callback(data);
             });
         };
         $scope.addKA = function (SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark) {
             $db.add('Finacial_KeepAccount'
                 , 'SuitType,ItemText,MoneyFlowDirect,Cash,AccountType,RecordDate,Remark, account'
                 , [SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark, g_user]);
         };
         $scope.updateKA = function (id, SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark) {
             $db.update('Finacial_KeepAccount'
                 , 'SuitType,ItemText,MoneyFlowDirect,Cash,AccountType,RecordDate,Remark'
                 , [SuitType, ItemText, MoneyFlowDirect, Cash, AccountType, RecordDate, Remark]
                 , 'id=' + id.toString());
         };
         $scope.deleteKA = function (id) {
             $db.delete('Finacial_KeepAccount', 'id=' + id.toString());
         };
         $scope.Finacial_SuitClass = [
             {MainClass: '基本生活', SuitType: '餐饮饮食'}
             , {MainClass: '基本生活', SuitType: '柴米油盐'}
             , {MainClass: '美容化妆', SuitType: '服饰装扮'}
             , {MainClass: '收入', SuitType: '福利津贴'}
             , {MainClass: '收入', SuitType: '工资'}
             , {MainClass: '美容化妆', SuitType: '化妆品美容'}
             , {MainClass: '交通通讯', SuitType: '话费网费'}
             , {MainClass: '交通通讯', SuitType: '交通费'}
             , {MainClass: '人情往来', SuitType: '借出'}
             , {MainClass: '投资', SuitType: '理财投资'}
             , {MainClass: '文化娱乐', SuitType: '旅游娱乐'}
             , {MainClass: '收入', SuitType: '其他收入'}
             , {MainClass: '其他支出', SuitType: '其他支出'}
             , {MainClass: '人情往来', SuitType: '人际往来'}
             , {MainClass: '基本生活', SuitType: '日常用品'}
             , {MainClass: '文化娱乐', SuitType: '书报音像'}
             , {MainClass: '文化娱乐', SuitType: '数码产品'}
             , {MainClass: '基本生活', SuitType: '水果零食'}
             , {MainClass: '基本生活', SuitType: '物业水电'}
             , {MainClass: '人情往来', SuitType: '孝敬长辈'}
             , {MainClass: '基本生活', SuitType: '医药保健'}
             , {MainClass: '文化娱乐', SuitType: '运动健身'}
         ];
         $scope.currDA = {
             title: '新增'
             , id: 0
             , RecordDate: new Date()
             , SuitType: ''
             , ItemText: ''
             , Cash: 0
             , Income: false
             , Remark: ''
         }
         $scope.arrageData = function () {
             var _data = $scope.dailyAccount;
             if (_data.length > 0) {
                 _data[0].ext_displayDivider = '';
                 if (_data.length > 1) {
                     var lastDA = _data[0];
                     for (var i = 1; i < _data.length; i++) {
                         _data[i].ext_displayDivider = 'none';
                         if (new Date(_data[i].RecordDate) < new Date(lastDA.RecordDate)) {
                             _data[i].ext_displayDivider = '';
                             lastDA = _data[i];
                         }
                     }
                 }
             }
         };
         $scope.remove = function (da) {
             $ionicPopup.confirm({
                 title: 'Confrim',
                 template: 'Do you really want to delete?',
                 scope: $scope,
                 buttons: [
                     {
                         text: '<b>Yes</b>',
                         type: 'button-positive',
                         onTap: function (e) {
                             //$scope.dailyAccount.splice($scope.dailyAccount.indexOf(da), 1);
                             $scope.deleteKA(da.id);
                             $scope.loadDate();
                         }
                     },
                     {
                         type: 'button-canceldark',
                         text: '<b>Cancel</b>',
                         onTap: function (e) {
                             console.log('cancel delete');
                         }
                     }
                 ]
             });
         };
         $scope.showDetail = function (da) {
             if (da == undefined) {
                 // 新增
                 $scope.currDA.title = '新增';
                 $scope.currDA.id = 0;
                 $scope.currDA.RecordDate = new Date();
                 $scope.currDA.SuitType = '';
                 $scope.currDA.ItemText = '';
                 $scope.currDA.Cash = 0;
                 $scope.currDA.Income = false;
                 $scope.currDA.Remark = '';
             } else {
                 // 读取
                 $scope.currDA.title = '编辑';
                 $scope.getKA(function (data) {
                         if (data.length > 0) {
                             var item = data[0];
                             $scope.currDA.id = item.id;
                             $scope.currDA.RecordDate = new Date(item.RecordDate);
                             $scope.currDA.SuitType = item.SuitType;
                             $scope.currDA.ItemText = item.ItemText;
                             $scope.currDA.Cash = item.Cash;
                             $scope.currDA.Income = (item.MoneyFlowDirect == '入账');
                             $scope.currDA.Remark = item.Remark;
                         }
                     }
                     , ' id = ' + da.id);
             }
             $scope.openModal();
         }
         $scope.save = function () {
             //log(angular.toJson($scope.currDA));
             if ($scope.currDA.SuitType == ''
                 || $scope.currDA.SuitType.indexOf('账目类型') >= 0) {
                 $alertPopup('账目类型没有选定哦');
                 return;
             }
             var _moneyFlowDirection = '出账';
             if ($scope.currDA.Income) _moneyFlowDirection = '入账';
             if ($scope.currDA.id == 0) {
                 // 新增
                 $scope.addKA(
                     $scope.currDA.SuitType
                     , $scope.currDA.ItemText
                     , _moneyFlowDirection
                     , $scope.currDA.Cash
                     , '我的钱包'
                     , dateFormat($scope.currDA.RecordDate, 'ymd')
                     , $scope.currDA.Remark
                 );
                 $scope.closeDetail();
                 $scope.loadDate();
             }
             else {
                 // 更新
                 $ionicPopup.confirm({
                     title: 'Confrim',
                     template: 'Do you really want to update?',
                     scope: $scope,
                     buttons: [
                         {
                             text: '<b>Yes</b>',
                             type: 'button-positive',
                             onTap: function (e) {
                                 $scope.updateKA(
                                     $scope.currDA.id
                                     , $scope.currDA.SuitType
                                     , $scope.currDA.ItemText
                                     , _moneyFlowDirection
                                     , $scope.currDA.Cash
                                     , '我的钱包'
                                     , dateFormat($scope.currDA.RecordDate, 'ymd')
                                     , $scope.currDA.Remark
                                 );
                                 $scope.closeDetail();
                                 $scope.loadDate();
                             }
                         },
                         {
                             type: 'button-canceldark',
                             text: '<b>Cancel</b>',
                             onTap: function (e) {
                                 console.log('cancel update');
                             }
                         }
                     ]
                 });
             }
         }
         // 弹窗
         $ionicModal.fromTemplateUrl('detail.html', {
             scope: $scope,
             animation: 'slide-in-up'
         }).then(function (modal) {
             $scope.modal = modal;
         });
         $scope.openModal = function () {
             $scope.modal.show();
         };
         $scope.closeDetail = function () {
             $scope.modal.hide();
         }
         $scope.$on('$destroy', function () {
             $scope.modal.remove();
         });
         $scope.loadDate = function () {
             $scope.getKA(function (data) {
                 for (var i = 0; i < data.length; i++) {
                     var _d = data[i];
                     _d['ext_displayDivider'] = 'none';
                     _d['ext_TextColor'] = 'black';
                     if (_d.MoneyFlowDirect == '入账')_d['ext_TextColor'] = 'blue';
                 }
                 $scope.dailyAccount = data;
                 $scope.arrageData();
             });
         }
         // start
         $scope.loadDate();
     }])
 ;
说明:
- arrageData()函数根据(按日期倒序)排序好的数据,设置当日最后一条数据(因为是倒序,所以采用最后一条)的ext_displayDivider属性为none,如此实现在“日期-当日各项收支项”的显示效果——按日分割后来发觉也可以用Ionic的Card,当然也许也有第三方控件可以直接用了。
- $ionicModal调用的弹窗功能,弹出的是一个完整的页面,本项目为了简便,就直接写在了同页面里“< script id="detail.html" type="text/ng-template">”
日常视图
HTML部分
<ion-view view-title="DailyActivity">
<ion-nav-title><b>日常</b></ion-nav-title>
<ion-content class="has-tabs">
<br/>
<div id='calendar'></div>
</ion-content> <!--弹出内容-->
<script id="detail.html" type="text/ng-template">
<ion-modal-view>
<ion-header-bar>
<h1 class="title">活动 / 计划</h1>
<button class="button" ng-click="closeDetail()">关闭</button>
</ion-header-bar>
<ion-content>
<div class="item-input-inset">
<label class="item-input-wrapper">
<i class="icon ion-android-calendar"></i> 
<span>{{act.tDate}}</span>
</label>
 
<span>{{act.id}}</span>
 
<!--<a class="button button-small" ng-click="save()">Save</a>-->
</div>
<div class="list card">
<div class="item item-divider">
事务
</div>
<div class="item item-body">
<label class="item-input">
<textarea style="background-color: whitesmoke" ng-model="act.Business"></textarea>
</label>
</div>
<div class="item item-divider">
学习
</div>
<div class="item item-body">
<label class="item-input">
<textarea style="background-color: whitesmoke" ng-model="act.Study"></textarea>
</label>
</div>
<div class="item item-divider">
健康
</div>
<div class="item item-body">
<label class="item-input">
<textarea style="background-color: whitesmoke" ng-model="act.Health"></textarea>
</label>
</div>
<div class="item item-divider">
运动
</div>
<div class="item item-body">
<label class="item-input">
<textarea style="background-color: whitesmoke" ng-model="act.Sport"></textarea>
</label>
</div>
<div class="item item-divider">
其他
</div>
<div class="item item-body">
<label class="item-input">
<textarea style="background-color: whitesmoke" ng-model="act.Others"></textarea>
</label>
</div>
</div>
</ion-content>
</ion-modal-view>
</script>
</ion-view>
JavaScript部分
 angular.module('pdm')
     .controller('Ctrl_DailyActivity',
     ['$scope', '$ionicModal', '$db', '$cordovaToast', '$alertPopup'
         , function ($scope, $ionicModal, $db, $cordovaToast, $alertPopup) {
         // BLL
         $scope.getDA = function (callback, cndt) {
             var sql = "SELECT * FROM Life_DailyActivity WHERE 1=1 ";
             if (cndt != undefined && cndt != '')sql += (' AND ' + cndt);
             sql += ' ORDER BY Date';
             $db._exec(sql, [], function (rst) {
                 var data = [];
                 for (var i = 0; i < rst.rows.length; i++) data.push(rst.rows.item(i));
                 callback(data);
             });
         };
         $scope.addDA = function (Date, Business, Study, Health, Sport, Others, Remark, callback) {
             var tbl = 'Life_DailyActivity';
             var fields = 'account,Date,Business,Study,Health,Sport,Others,Remark';
             var valueArr = [g_user, Date, Business, Study, Health, Sport, Others, Remark];
             var _param = '';
             for (var i = 0; i < fields.split(',').length; i++)_param += ',?';
             _param = _param.substr(1);
             var sql = 'INSERT INTO ' + tbl + '(' + fields + ') values(' + _param + ')';
             $db._exec(sql, valueArr,
                 function (rst) {
                     if (callback != undefined && callback != null) callback(rst);
                     else $cordovaToast.showShortCenter('add to ' + tbl + ' success');
                 });
         };
         $scope.updateDA = function (Date, Business, Study, Health, Sport, Others, Remark) {
             $db.update('Life_DailyActivity'
                 , 'Business,Study,Health,Sport,Others,Remark'
                 , [Business, Study, Health, Sport, Others, Remark]
                 , "Date='" + Date + "'"
                 , true);
         }
         $scope.editing = false;
         $scope.act = {
             id: 0,
             tDate: dateFormat(new Date(), 'ymd'),
             Business: '',
             Study: '',
             Health: '',
             Sport: '',
             Others: '',
             Remark: ''
         };
         var _lastDate = $scope.act.tDate;
         $scope.loadData = function () {
             $scope.getDA(function (data) {
                     $scope.act.Business = '';
                     $scope.act.Study = '';
                     $scope.act.Health = '';
                     $scope.act.Sport = '';
                     $scope.act.Others = '';
                     $scope.act.Remark = '';
                     if (data.length > 0) {
                         var item = data[0];
                         $scope.act.id = item.id;
                         $scope.act.Business = item.Business;
                         $scope.act.Study = item.Study;
                         $scope.act.Health = item.Health;
                         $scope.act.Sport = item.Sport;
                         $scope.act.Others = item.Others;
                         $scope.act.Remark = item.Remark;
                         if ($scope.act.id > 0) {
                             $db._exec("delete from Life_DailyActivity where Date='" + $scope.act.tDate + "' and id!=" + $scope.act.id);
                         }
                     } else {
                         $scope.addDA($scope.act.tDate
                             , $scope.act.Business
                             , $scope.act.Study
                             , $scope.act.Health
                             , $scope.act.Sport
                             , $scope.act.Others
                             , $scope.act.Remark
                             , function (rst) {
                                 $scope.act.id = rst.insertId;
                             }
                         );
                     }
                 },
                 "Date='" + $scope.act.tDate + "'");
         }
         $scope.save = function () {
             $scope.updateDA($scope.act.tDate
                 , $scope.act.Business
                 , $scope.act.Study
                 , $scope.act.Health
                 , $scope.act.Sport
                 , $scope.act.Others
                 , $scope.act.Remark
             );
         }
         // 监听数据变化
         $scope.$watch('act.Business', function (newValue, oldValue, scope) {
             if ($scope.editing && newValue != oldValue)$scope.save();
         });
         $scope.$watch('act.Study', function (newValue, oldValue, scope) {
             if ($scope.editing && newValue != oldValue)$scope.save();
         });
         $scope.$watch('act.Health', function (newValue, oldValue, scope) {
             if ($scope.editing && newValue != oldValue)$scope.save();
         });
         $scope.$watch('act.Sport', function (newValue, oldValue, scope) {
             if ($scope.editing && newValue != oldValue)$scope.save();
         });
         $scope.$watch('act.Others', function (newValue, oldValue, scope) {
             if ($scope.editing && newValue != oldValue)$scope.save();
         });
         $scope.initData = function () {
             var events_data = [];
             // 日常
             $scope.getDA(function (data) {
                 var op = [];
                 op['Business'] = '#387EF5';
                 op['Study'] = '#FFC900';
                 op['Health'] = '#EF473A';
                 op['Sport'] = '#33CD5F';
                 op['Others'] = '#B2B2B2';
                 for (var i = 0; i < data.length; i++) {
                     var dd = data[i];
                     for (var k in op) {
                         if (dd[k.toString()] != undefined && dd[k.toString()] != '') {
                             var item = [];
                             item['color'] = op[k];
                             item['title'] = dd[k.toString()].replace('\n','|').substring(0, 10);
                             item['start'] = new Date(dd['Date']);
                             events_data.push(item);
                         }
                     }
                 }
                 $('#calendar').fullCalendar('destroy');
                 $('#calendar').fullCalendar({
                     header: {
                         left: 'prev,next today',
                         center: 'title',
                         right: 'month'//,agendaWeek,agendaDay'
                     },
                     firstDay: 1,
                     events: events_data,
                     // 点击空白
                     dayClick: function (date, allDay, jsEvent, view) {
                         var selDate = $.fullCalendar.formatDate(date, 'yyyy-MM-dd');//格式化日期
                         $scope.act.tDate = selDate;
                         $scope.loadData();
                         $scope.openModal();
                     },
                     //单击事件项时触发
                     eventClick: function (calEvent, jsEvent, view) {
                         $scope.act.tDate = dateFormat(calEvent.start,'ymd');
                         $scope.loadData();
                         $scope.openModal();
                     }
                 });
             });
         }
         // 弹窗
         $ionicModal.fromTemplateUrl('detail.html', {
             scope: $scope,
             animation: 'slide-in-up'
         }).then(function (modal) {
             $scope.modal = modal;
         });
         $scope.openModal = function () {
             $scope.modal.show();
             $scope.editing = true;
         };
         $scope.closeDetail = function () {
             $scope.initData();
             $scope.editing = false;
             $scope.modal.hide();
         }
         $scope.$on('$destroy', function () {
             $scope.modal.remove();
         });
         // start
         $scope.initData();
     }])
 ;
说明:
- 日常数据的录入,采用了“即变即更新”的模式,这里使用$watch函数来监听数据变化。同时为了数据更新功能的便利性,在用户点击某一日弹框时,自动判断当日数据是否存在,不存在则插入空数据。
打包发布
生成Android平台安装包
使用命令:
cordova platform add android
cordova build android
(*注意,如果以上步骤出错,常见原因有:
- 安装的Android SDK和打包的SDK版本不对,下载相应SDK
- 环境变量没有配置好
- 安装最新node.js
)
*附录
【源码文件】
【APK文件】
作者:Ken
出处:http://www.cnblogs.com/glife/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【Ionic+AngularJS 开发】之『个人日常管理』App(二)的更多相关文章
- 【Ionic+AngularJS 开发】之『个人日常管理』App(一)
		写在前面的话 过去一年自己接触了不少手机前端开发,得益于现在手机性能的提升和4G普及,感觉使用混合技术开发手机App已经可以满足越来越多的应用场景了.新年伊始,对自己2016年所学知识做一个阶段性 ... 
- 实践分享:开始用Cordova+Ionic+AngularJS开发App
		http://www.cocoachina.com/webapp/20150707/12395.html 本文是一篇关于我本人在使用Cordova+Ionic以及AngularJS开发移动App的过程 ... 
- Ionic+AngularJS  开发的页面在微信公众号下显示不出来原因查究
		ionic 页面 微信浏览器遇到的坑 公司的微信公众号一部分页面是用AngularJS+Ioinc开发,发现在本地浏览器测试的时候都没问题,传到服务器在微信公众号下跑就出问题来,经查是: index- ... 
- ionic+angularjs开发hybrid App(环境配置+创建测试项目)
		本文使用的系统是win10 因为后期需要使用nodejs 所以先把node装好 https://nodejs.org/download/ 下载JDK并配置Java运行环境 http://www.ora ... 
- Linux 笔记 - 第十三章 Linux 系统日常管理之(二)Linux 防火墙和任务计划
		博客地址:http://www.moonxy.com 一.前言 Linux 下的的防火墙功能是非常丰富的,作为 Linux 系统工程师有必要了解一下.防火墙一般分为硬件防火墙和软件防火墙.但是,不管是 ... 
- 【python测试开发栈】—python内存管理机制(二)—垃圾回收
		在上一篇文章中(python 内存管理机制-引用计数)中,我们介绍了python内存管理机制中的引用计数,python正是通过它来有效的管理内存.今天来介绍python的垃圾回收,其主要策略是引用计数 ... 
- Cordova Ionic AngularJS
		实践分享:开始用Cordova+Ionic+AngularJS开发App http://www.cocoachina.com/webapp/20150707/12395.html 
- 搭建 AngularJS+Ionic+Cordova 开发环境并运行一个demo
		目前的手机APP有三类:原生APP,WebAPP,HybridApp:HybridApp结合了前两类APP各自的优点,越来越流行. Cordova就是一个中间件,让我们把WebAPP打包成Hybrid ... 
- WebApp开发框架Ionic+AngularJS+Cordova
		目前的手机APP有三类:原生APP.WebAPP.HybridApp:HybridApp结合了前两类APP各自的优点,越来越流行. Ionic Ionic是一个新的.可以使用HTML5构建混合移动应用 ... 
随机推荐
- MAC apache 2.4 启用目录访问
			1. 打开 httpd.conf 文件,在Options 后面添加 "Indexes",如下: <Directory "/Users/ChenShuo/Docume ... 
- mysql用存储过程插入百万条数据, 及查询优化
			查看所有存储过程: show procedure status; 查看详细存储过程 ptest: show create procedure ptest; 存储过程插入数据: create table ... 
- javascript之日期对象
			学习要点: 日期对象 将日期对象转换为字符串 将日期对象中的日期和时间转换为字符串 日期对象中的日期 日期对象中的时间 设置日期对象中的日期 设置日期对象中的时间 与毫秒相关的方法 一.日期对象 在j ... 
- 利用智能手机(Android)追踪一块磁铁(转)
			利用智能手机(Android)追踪一块磁铁(一) 利用智能手机(Android)追踪一块磁铁(二) 利用智能手机(Android)追踪一块磁铁(三) 
- STM32+NRF24L01无线(转)
			源:STM32+NRF24L01无线 硬件SPI和模拟SPI源码: nrf24发送(模拟SPI)BHS-STM32.rar nrf24接收(模拟SPI)BHS-STM32.rar nrf24发送(硬件 ... 
- Mapreduce 反向索引
			反向索引主要用于全文搜索,就是形成一个word url这样的结构 file1: MapReduce is simple file2: MapReduce is powerful is simple f ... 
- ucos互斥信号量解决优先级反转问题
			在可剥夺性的内核中,当任务以独占方式使用共享资源的时候,会出现低优先级任务高于高优先级任务运行的情况,这种情况叫做优先级反转,对于实时操作系统而言,这是一场灾难,下面我们来说说优先级反转的典型环境. ... 
- UVa 231 - Testing the CATCHER
			题目大意:一种拦截导弹能拦截多枚导弹,但是它在每次拦截后高度不会再升高,给出导弹的序列,问最多能拦截多少枚导弹? 最长递减子序列问题. #include <cstdio> #include ... 
- iOS 界面布局,设置约束
			1. 设置控件的宽度是父视图的宽度的1/2 在控件上按住ctrl,按住鼠标左键,拖动到父视图,这时出来一个选项,选中aspect 在Multiplier中填上1:2 即可,其它的比例也是这样 2. 设 ... 
- iOS bug  之 H5 页面没有弹出提示框
			描述:在安卓上有提示框,但是在iOS上没有提示框. step 1: 失误,是我没有在正确的位置设置网址. step 2: 修改之后,测试页能弹出提示框,但是正式的页面没有提示框. step 3: 我输 ... 
