.
204 Ionic Side Menu Record Book Apps From Scratch
Building On Codepen Platform
This tutorial demonstrates the development of Master-Detail Apps using Ionic Framework. The concept has been explained in the previous tutorial, http://basic-steps.blogspot.my/2017/01/203-ionic-side-menu-record-book-apps.html. While the previous tutorial uses the dummy data for parameter passing, this tutorial uses pre-populated local data storage.
Objective:
1) Populate local data storage.
2) Fetch Master Records from storage.
3) Use JS Reduce function to calculate the count and total value of the Detail records that belong to each Master records.
4) Display the Master record items with the count and total value (obtained from Obj.3).
5) When an item on the list is selected, pass the item to Details page as parameter.
6) Open the Details page and display the parameter value.
Kickstarter Codes:
1) Prepare Master Page and Detail Page in HTML code
HTML
<html>
<head>
<meta charset="utf-8">
<title>Diary</title>
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
<!-- Internal Library
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<script src="lib/ionic/js/ionic.bundle.js"></script>
-->
<!-- Cloud Library -->
<link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">
<script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
<!-- Needed for Cordova/PhoneGap (will be a 404 during development) -->
<script src="cordova.js"></script>
</head>
<body ng-app="app">
<div>
<div>
<ion-nav-bar class="bar-stable">
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>
<ion-nav-view></ion-nav-view>
</div>
</div>
<script id="home.html" type="text/ng-template">
<ion-view title="Home" id="page1">
<ion-nav-buttons side="right" class="has-header">
<button class="button button-icon" ng-click="insertRecord()">
<i class="icon ion-compose"></i>
</button>
</ion-nav-buttons>
<ion-content padding="true" class="has-header">
<h2>MASTER</h2>
<div class = "row">
<div class = "col"><b>Date</b></div>
<div class = "col"><b>Count</b></div>
<div class = "col"><b>Total</b></div>
</div>
<div class = "row" ng-class-odd="'odd'" ng-class-even="'even'"
ng-repeat="master in masters"
ui-sref="menu.details({param1:{{master.date}}})">
<div class = "col">{{master.date | date:'yyyy-MM-dd HH:mm:ss Z'}}</div>
<div class = "col">{{master.count}}</div>
<div class = "col">{{master.total}}</div>
</div>
</ion-content>
</ion-view>
</script>
<script id="details.html" type="text/ng-template">
<ion-view title="Details" id="page4">
<ion-nav-buttons side="right" class="has-header">
<button class="button button-icon" ng-click="insertRecord()">
<i class="icon ion-compose"></i>
</button>
</ion-nav-buttons>
<ion-content padding="true" class="has-header">
{{date | date:'yyyy-MM-dd HH:mm:ss Z'}}
</ion-content>
</ion-view>
</script>
<script id="cart.html" type="text/ng-template">
<ion-view title="Cart" id="page2">
<ion-content padding="true" class="has-header"></ion-content>
</ion-view>
</script>
<script id="cloud.html" type="text/ng-template">
<ion-view title="Cloud" id="page3">
<ion-content padding="true" class="has-header"></ion-content>
</ion-view>
</script>
<script id="menu.html" type="text/ng-template">
<ion-side-menus enable-menu-with-back-views="false">
<ion-side-menu-content>
<ion-nav-bar class="bar-stable">
<ion-nav-back-button></ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-toggle="left"></button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-nav-view name="side-menu21"></ion-nav-view>
</ion-side-menu-content>
<ion-side-menu side="left" id="side-menu21">
<ion-header-bar class="bar-stable">
<div class="title">Menu</div>
</ion-header-bar>
<ion-content padding="false" class="side-menu-left has-header ">
<ion-list id="menu-list1">
<ion-item id="menu-list-item1" ui-sref="menu.home" menu-close="">Home</ion-item>
<ion-item id="menu-list-item2" ui-sref="menu.cart" menu-close="">Cart</ion-item>
<ion-item id="menu-list-item3" ui-sref="menu.cloud" menu-close="">Cloud</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>
</script>
<script id="insertRecord.html" type="text/ng-template">
<div class="modal">
<!-- Modal header bar -->
<ion-header-bar class="bar-secondary">
<h1 class="title">Insert Record</h1>
<button class="button button-clear button-positive" ng-click="closeInsertRecord()">Cancel</button>
</ion-header-bar>
<!-- Modal content area -->
<ion-content>
<form ng-submit="submitInsertRecord(record)">
<div class="list">
<label class="item item-input">
<input type="date" placeholder="Transaction Date" ng-model="record.date">
</label>
<label class="item item-input">
<input type="text" placeholder="Transaction Cost" ng-model="record.cost">
</label>
</div>
<div class="padding">
<button type="submit" class="button button-block button-positive">Insert Record</button>
</div>
</form>
</ion-content>
</div>
</script>
</body>
</html>
|
CSS
.odd {
background-color: WhiteSmoke ;
}
.even {
background-color: Lavender ;
}
|
2) Prepare Master Page and Details Page in JS Code
JS
angular.module('app', ['ionic'])
.factory('DataTree', function() {
return {
all: function() {
var strData = window.localStorage['datatree1'];
if(strData) {
//console.log(strDataGroups);
return angular.fromJson(strData);
}
return [];
},
save: function(strData) {
window.localStorage['datatree1'] = angular.toJson(strData);
}
}
})
.controller('homeCtrl', ['$scope', '$stateParams', '$ionicModal', 'DataTree',
function ($scope, $stateParams, $ionicModal, DataTree) {
// Initialize dataGroups
var initDataTree = function() {
//initialize with dummy data
var dataTrunk ={"daily":[{"date":978278400000,"items":[{"date":978278400000,"cost":10},{"date":978278400000,"cost":10}],"summary":{}},{"date":1485878400000,"items":[{"date":1485878400000,"cost":5},{"date":1485878400000,"cost":6}],"summary":{}}],"settings":[]};
console.log("Data initialized.");
DataTree.save(dataTrunk);
}
// Get data from storage
// If data length=0, call initDataTree
var dataTrunk=DataTree.all();
if (dataTrunk.length==0){
console.log("Init data tree.");
initDataTree();
}
// Else
else{
console.log("Data exists.");
//console.log(dataTrunk);
//console.log(dataTrunk.daily);
//console.log(dataTrunk.daily[0].items[0].cost);
}
//init master records to be displayed in list
$scope.masters=[];
//function to get total cost for each master item
function getSum(total, x) {
return total + x.cost;
}
for(i in dataTrunk.daily){
array1=dataTrunk.daily[i].items;
// two ways of using js reduce function:
// a) call getSum function
// b) execute inline function
// both a and b will produce the same value
var a=array1.reduce(getSum,0);
var b=array1.reduce(function(total, x) { return total + x.cost; }, 0);
//we can use either var a or b for total
$scope.masters.push({date:dataTrunk.daily[i].date,
count:dataTrunk.daily[i].items.length,
total:a
});
}//for
console.log($scope.masters);
// Create and load the Modal
$ionicModal.fromTemplateUrl('insertRecord.html', function(modal) {
$scope.insertRecordModal = modal;
}, {
scope: $scope,
animation: 'slide-in-up'
});
// Called when the form is submitted
$scope.submitInsertRecord = function(record) {
var epochDate = new Date(record.date);
epochDate.setHours(0, 0, 0);
epochDate = epochDate.getTime();
$scope.datagroups.push({
date: epochDate,
cost: record.cost
});
$scope.dataGroups[0].daily=$scope.datagroups;
DataBag.save($scope.dataGroups);
$scope.insertRecordModal.hide();
record.date="";
record.cost = "";
};
// Open our new task modal
$scope.insertRecord = function() {
$scope.insertRecordModal.show();
};
// Close the new task modal
$scope.closeInsertRecord = function() {
$scope.insertRecordModal.hide();
};
}])
.controller('detailsCtrl', ['$scope', '$stateParams',
function ($scope, $stateParams) {
//console.log($stateParams.param1);
$scope.date=$stateParams.param1;
}])
.controller('cartCtrl', ['$scope', '$stateParams',
function ($scope, $stateParams) {
}])
.controller('cloudCtrl', ['$scope', '$stateParams',
function ($scope, $stateParams) {
}])
.controller('menuCtrl', ['$scope', '$stateParams',
function ($scope, $stateParams) {
}])
.config(function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('menu.home', {
url: '/page1',
views: {
'side-menu21': {
templateUrl: 'home.html',
controller: 'homeCtrl'
}
}
})
.state('menu.details', {
url: '/page4',
params: {
param1: "1"
},
views: {
'side-menu21': {
templateUrl: 'details.html',
controller: 'detailsCtrl'
}
}
})
.state('menu.cart', {
url: '/page2',
views: {
'side-menu21': {
templateUrl: 'cart.html',
controller: 'cartCtrl'
}
}
})
.state('menu.cloud', {
url: '/page3',
views: {
'side-menu21': {
templateUrl: 'cloud.html',
controller: 'cloudCtrl'
}
}
})
.state('menu', {
url: '/side-menu21',
templateUrl: 'menu.html',
controller: 'menuCtrl'
})
$urlRouterProvider.otherwise('/side-menu21/page1')
});
|
3) Outcome.
4) Sending Object as Parameter.
4.1) HTML
<ion-view title="Home" id="page1">
<ion-nav-buttons side="right" class="has-header">
<button class="button button-icon" ng-click="insertRecord()">
<i class="icon ion-compose"></i>
</button>
</ion-nav-buttons>
<ion-content padding="true" class="has-header">
<h2>MASTER</h2>
<div class = "row">
<div class = "col"><b>Date</b></div>
<div class = "col"><b>Count</b></div>
<div class = "col"><b>Total</b></div>
</div>
<div class = "row" ng-class-odd="'odd'" ng-class-even="'even'"
ng-repeat="master in masters"
ui-sref="menu.details({param1:{{master}}})">
<div class = "col">{{master.date | date:'yyyy-MM-dd HH:mm:ss Z'}}</div>
<div class = "col">{{master.count}}</div>
<div class = "col">{{master.total}}</div>
</div>
</ion-content>
</ion-view>
|
4.2) JS
for(i in dataTrunk.daily){
array1=dataTrunk.daily[i].items;
// two ways of using reduce function:
// a) call getSum function
// b) execute inline function
// both a and b will produce the same value
var a=array1.reduce(getSum,0);
var b=array1.reduce(function(total, x) { return total + x.cost; }, 0);
//we can use either var a or b for total
$scope.masters.push({date:dataTrunk.daily[i].date,
count:dataTrunk.daily[i].items.length,
total:a,
items:dataTrunk.daily[i].items
});
}//for
|
No comments:
Post a Comment