費用跟蹤應用採用了Wijmo5和Ionic Framework建立,目的是構建一個hybird app。前端
咱們基於《Mobile first! Wijmo 5 + Ionic Framework之:Hello World!》的環境,將在本教程中完成費用跟蹤App的構建。下面的代碼結構是本教程完成要達到的效果,請預先建立好文件和目錄。git
www/ -->-->/ -->/ -->-->-->/ -->/ -->/ -->/ --> angularJs視圖代碼目錄(經過UI-/ --> 第三方類庫, 包括Ionic, Wijmo, jQuery等
在費用跟蹤App中,咱們先要建立Data Model,E-R圖以下angularjs
Category:開支分類github
Expense:開支記錄api
Budget: 預算(下面會用到)數組
在代碼中,咱們須要在www/js/services構建AngularJs Services來對數據模型進行建模。咱們會用到HTML5的localStorage進行數據本地存儲, 採用的格式爲JSON。 須要注意的是,HTML5本地存儲只能存字符串,任何格式存儲的時候都會被自動轉爲字符串,因此讀取的時候,須要本身進行類型的轉換。目前咱們實現的是HTML5 本地存儲,有興趣的讀者還可移植爲RESTful API、SQLite等數據存儲方法。app
運行demo後,經過Chrome調試查看的本地存儲截圖:ionic
在開支歷史頁面中,提供了2個功能:瀏覽開支歷史記錄、刪除開支記錄。爲了實現這些功能,在www\js\controllers\history.js文件中,添加以下代碼:ide
$scope.expenses = ExpenseSvc.getExpensesWithCategory();
這行代碼提供了返回本地存儲的開支記錄。ExpenseSvc 服務,不只返回了開支對象,同時也返回了開支分類。基於這些數據,在函數
www\templates\history.tpl.htm文件中,在ion-context指令內添加Ionic的ion-list指令,代碼以下:
{{ expense.title }} {{ expense.date | date: 'shortDate' }}
ion-list指令,用於生成排序的HTML列表,其子標籤ion-item指令用於生成HTML列表項。 在ngRepeat指令中,咱們使用了「track by」,目的是在對開支集合修改時提高性能,相關教程可參考博客《Using Track-By With ngRepeat In AngularJS 1.2 》。
如今添加刪除開支記錄按鈕,用於向左滑動出現刪除按鈕、點擊刪除可刪除開支記錄。
在ion-item標籤關閉前添加ion-option-button標籤,代碼以下:
Delete
ion-option-button 是Ionic提供的另外一個指令,用於在ion-item指令內試用。默認的,ion-option-button 是隱藏的,當在ion-item內向左滑動,則按鈕會可見。這個功能尤爲對小屏幕設備很是重要。另外,還可經過該指令內置的can-swipe來實現對這個權限的管理--若有的用戶不容許刪除操做權限。
在刪除函數中(控制器),可看到代碼片斷以下:
function confirmDelete(expenseId) { // delete expense by its id property $scope.expenses = ExpenseSvc.deleteExpense(expenseId); }
經過這個代碼,咱們調用ExpenseSvc服務的deleteExpense進行刪除指定的開支記錄(expenseId),同時這個方法也會返回開支記錄集合用於更新頁面數據。在真實的場景中,刪除記錄返回整個集合不是最理想的,但在此處咱們用於演示說明。可動手試着刪除幾行數據試試。
另外,在刪除這種比較危險的操做中,應該須要添加對話框再次提醒一下用戶。這裏咱們使用了Ionic提供的$ionicActionSheet service服務來實現。更新www\js\controllers\history.js控制器代碼的confirmDelete函數以下:
$scope.confirmDelete = hideSheet ='Are you sure that you\'d like to delete this expense?''Cancel''Delete' $scope.expenses =
ionicActionSheet服務提供了自定義接口,可實現各類提示對話框。上面代碼實現的提示對話框效果截圖以下:
點擊History頁面右上角的可實現手工建立一條新的開支記錄。在www\templates\createExpense.tpl.htm文件中,代碼以下:
Cancel Save
這裏使用ion-view 和 ion-content 指令進行內容展示。而後再添加Form,用ng-show指令驗證輸入內容---Wijmo的指令已經在輸入門限作了限制,故不須要驗證。同時Wijmo Calendar 和InputNumber應該是自解釋,ComboBox中可能不是。
ComboBox關聯數據模型中的開支分類,咱們經過其itemsSource屬性進行數據綁定。ComboBox的displayMemberPath 用於設置顯示內容,selectedItem的selectedValue用於選擇開支分類的id屬性。
在createExpense 控制器中,可看到以下的代碼片斷:
$scope.expense = Expense('', 0, Date(), '', $scope.categories =$scope.addExpense = $scope.cancel = 'app.overview'
上面的第一行代碼用於初始化一個開支記錄,用Expense的構造函數來實現,並賦值給$scope.expense對象。 開支分類,經過調用CategorySvc服務的接口,從localStorage得到數組。addExpense 方法用於提交新增的開支記錄,一樣用到了ExpenseSvc服務。最後一個函數$scope.canel使用了UI Router的 $state 服務,導航到主頁面。
運行app,截圖以下:
在前面幾節中,咱們分別學習瞭如何查看、建立、刪除開支記錄。在本節,咱們將經過Wijmo5的FlexGrid和CollectionView批量對開支記錄進行呈現,打開detailsGrid 模板文件,添加以下代碼片斷:
<ion-view title="Details Grid"> <!-- set overflow-scroll="true" and hand scrolling to native --> <ion-content class="has-header" overflow-scroll="true"> <wj-flex-grid auto-generate-columns="false" items-source="data" selection-mode="Row" row-edit-ending="rowEditEnding(s,e)" style="position:relative"> <wj-flex-grid-column width="2*" min-width="250" header="Title" binding="title"></wj-flex-grid-column> <wj-flex-grid-column width="*" min-width="100" header="Amount" binding="amount" format="c2"></wj-flex-grid-column> <wj-flex-grid-column width="*" min-width="100" header="Date" binding="date"></wj-flex-grid-column> <wj-flex-grid-column width="2*" min-width="250" header="Description" binding="description"></wj-flex-grid-column> </wj-flex-grid> </ion-content> <ion-footer-bar class="bar button-bar-footer"> <div class="button-bar"> <button type="button" class="button button-dark icon-left ion-close" on-tap="cancel()">Cancel</button> <button type="button" class="button button-balanced icon-left ion-checkmark" ng-disabled="!data.itemsEdited.length" on-tap="update()">Save</button> </div> </ion-footer-bar> </ion-view>
在FlexGrid指令下面,咱們添加了2個按鈕,Cancel和Save,分別用於當點擊的時候進行取消和存儲操做,數據存儲於localStorage。其中,Save按鈕的默認不可用,經過ngDisabled的表達式進行控制。
FlexGrid 指令,用於在模板內生成Wijmo5的FlexGrid 控件。咱們使用itemsSource 進行數據源綁定,同時經過autoGenerateColumns=」false」關閉自動生成數據列,以及SelectMode類型爲整行Row。同時也設置了FlexGrid的rowEditEnding事件,用於驗證數據輸入。在FlexGrid內部,定義了Columns,分別指定了header、binding、width。
以下代碼是detailsGrid 控制器片斷:
$scope.data = $scope.data.trackChanges = $scope.update = $scope.cancel = 'app.overview'$scope.rowEditEnding = expense = $scope.data.currentEditItem, isValid = isExpenseValid(expense); (! expense &&!== '' &&< 55 &&&&&&>= 0
上面代碼的第一行,經過從localStorage 加載數據,而後初始化CollectionView的對象,繼而賦值給$scope.data對象,用於給前端HTML進行Data-Source綁定數據源。
接下來看cancel、update方法,cancel方法和上面的同樣,使用了UI Router的$state服務進行回到首頁。update方法,先進行數據判斷,經過覈查$scope.data.itemsEdited.length是否有效(是否有開支記錄變動),而後再調用ExpenseSvc 進行數據修改,對localStorage數據進行存儲處理。
最後,FlexGrid的rowEditEnding事件觸發了rowEditEnding函數,即當row修改完成後還沒有cancel、update前觸發。在這裏進行有效性判斷,若無效則cancel並返回。這裏,咱們使用了Wijmo 5提供的工具函數:isNumber和isDate來進行判斷。
運行Details Grid截圖以下:
修改app.routes.js 文件,從默認的history頁面到overview頁面:
$urlRouterProvider.otherwise('/app/history''/app/overview');
這個細小的改變使得UI Router 會對沒有明確重定向的,均會導向overview頁面。
overview頁面代碼以下所示:
<ion-view title="Overview"> <ion-nav-buttons side="right"> <a class="button button-icon icon ion-plus" href="#/app/create"></a> </ion-nav-buttons> <ion-content class="has-header padding"> <div ng-show="hasExpenses"> <hgroup class="text-center padding-vertical"> <h2 class="title"> <span ng-class="expensesCssClass">{{ totalExpenses | currency }}</span> of {{ budget | currency }} </h2> <h4>{{ budgetMsg }}</h4> </hgroup> <wj-flex-chart items-source="categories"-type="Bar" binding-x="name"-content=""-mode="Point"="Tap the chart's bars to see history by category"-changed="selectionChanged(s)"-formatter="itemFormatter"="height: 400px;"> <wj-flex-chart-series binding="total"></wj-flex-chart-series> <wj-flex-chart-axis wj-property="axisX" format="c0"></wj-flex-chart-axis> <wj-flex-chart-axis wj-property="axisY" reversed="true" major-grid="false" axis-line="true"></wj-flex-chart-axis> </wj-flex-chart> </div> <div ng-hide="hasExpenses"> <h4 class="padding text-center">You haven'
上面的代碼,首先使用hgroup元素呈現了開支記錄的總和。下面接着使用了Wijmo 5 FlexChart 渲染了每一個開支分類的開支金額,在FlexChart 指令內,咱們指定了一些屬性,如數據序列、x、y軸,同時當點擊Bar的時候會觸發FlexChart的plot elements 事件,對當前分類詳情作列表呈現。
上面這些功能的實現,基於overview.js文件的邏輯:
$scope.budget =$scope.hasExpenses =$scope.totalExpenses =$scope.categories =$scope.expensesCssClass = 'energized'$scope.budgetMsg = $scope.totalExpenses <=? $filter('currency')($scope.budget - $scope.totalExpenses).concat(' until you reach your monthly limit''currency')($scope.totalExpenses - $scope.budget).concat(' over your monthly limit'$scope.expensesCssClass = 0 ===? 'dark'===? 'energized'>? 'assertive''balanced'$scope.selectionChanged = category = (sender.selection && category = $state.go('app.category-history'$scope.itemFormatter = (hitTestInfo.chartElement === engine.fill ==
預覽截圖以下: