เนื้อหาในตอนนี้จะเป็นการประยุกต์เพิ่มเติม และเพื่อให้เข้าใจการทำงาน
เราจะยังอยู่ในรูปแบบของระบบสมาชิก ของ app ionic material
จากเนื้อหาในตอนที่ผ่านมาก่อนๆ หน้า เราได้ศึกษาการใช้งานการจัดเก็บข้อมูล
ลงใน database บนมือถือด้วย SQLite แต่เราจะลองต่อยอด กรณีเรามีระบบสมาชิก
อยู่บนฝั่ง server บนอินเทอร์เน็ตหรือในเว็บไซต์ และต้องการให้สมาชิกล็อกอินผ่าน
app โดยนำค่ามาเช็คหรือตรวจสอบการล็อกอินที่ฝั่ง server ประมาณนี้ เป็นต้น
บทความเกี่ยวกับ ionic material ดูเพิ่มเติมได้ที่
ในที่นี้เราจะจำลอง server ที่เครื่องเพื่อสร้าง ตารางสมาชิก สำหรับทดสอบ
สร้างตารางชื่อ tbl_member ตามรูปแบบโครงสร้าง sql ดังนี้
-- -- Table structure for table `tbl_member` -- CREATE TABLE IF NOT EXISTS `tbl_member` ( `member_id` int(11) NOT NULL, `member_user` varchar(50) NOT NULL, `member_pass` varchar(50) NOT NULL, `member_phone` varchar(15) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Indexes for dumped tables -- -- -- Indexes for table `tbl_member` -- ALTER TABLE `tbl_member` ADD PRIMARY KEY (`member_id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `tbl_member` -- ALTER TABLE `tbl_member` MODIFY `member_id` int(11) NOT NULL AUTO_INCREMENT;
สร้างไฟล์ member_api.php
หลังจากสร้างตาราง tbl_member แล้ว ต่อไปจะเป็นการสร้างไฟล์ member_api.php
เป็นไฟล์สำหรับรับค่าและส่งค่าข้อมูลของระบบสมาชิก เราจะใช้รูปแบบ php อย่างง่าย
สำหรับสร้าง api สำหรับการล็อกอิน การสมัครสมาชิกใหม่ และการดึงข้อมูลสมาชิก
สมมติเราสร้างไฟล์ไว้ที่
http://192.168.8.103/app/api/member_api.php
โดย http://192.168.8.103 ก็คือ http://localhost
แต่เวลาที่เราทดสอบผ่าน app ต้องกำหนดเป็น ip เครื่องใน lan/wlan
ส่วนถ้าใช้จริงบน server ก็กำหนด url แบบเต็มได้เลย
<?php header("Content-type:application/json; charset=UTF-8"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); if(isset($_SERVER['HTTP_ORIGIN'])) { header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); header('Access-Control-Allow-Credentials: true'); // header('Access-Control-Max-Age: 86400'); // cache for 1 day } // Access-Control headers are received during OPTIONS requests if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { if(isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); if(isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"); exit(0); } // ส่วนการกำหนด header ให้กำหนดตามด้านบน ไม่เช่นนั้น app จะไม่สามารถส่งค่ามาได้ require_once("dbconnect.php"); $postdata = file_get_contents("php://input"); // ค่าที่ส่งมาจะถูกเก็บที่ไฟล์ if(isset($postdata)) { // ถ้ามีคาที่ส่งมา $_POST = json_decode($postdata,true); // แปลงค่าที่ส่งมาเป็นตัวแปร array $_POST } // ฟังกืชั่นเช็คตัวอักษรอย่างง่าย function check_char($str,$is_number=null){ if(isset($is_number)){ $patern = "1234567890"; }else{ $patern = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._-"; } $arr_allow_char = str_split($patern); $arr_str = str_split($str); $check_char_status=0; if($arr_str){ $check_char_status=1; foreach($arr_str as $v_char){ if(!in_array($v_char,$arr_allow_char)){ $check_char_status=0; break; } } } return $check_char_status; } $_error_msg = null; $_success_msg = null; if( isset($_POST['new_member']) && (isset($_POST['user']) && $_POST['user']!="") && (isset($_POST['pass']) && $_POST['pass']!="") && (isset($_POST['phone']) && $_POST['phone']!="") ){ // กรณีสมัครสมาชิกใหม่ $_res_User = $mysqli->real_escape_string(trim($_POST['user'])); $_res_Pass = $mysqli->real_escape_string(trim($_POST['pass'])); $_res_Phone = $mysqli->real_escape_string(trim($_POST['phone'])); if(strlen($_res_Phone)!=10 || check_char($_res_Phone,1)==0){ $_error_msg = "เบอร์มือถือ ต้องเป็นตัวเลข 10 หลัก"; } if(strlen($_res_Pass)<4 || strlen($_res_User)>13){ $_error_msg = "รหัสผ่าน ต้องมีความยาว 4 - 13 ตัวอักษร"; } if(check_char($_res_User)==0){ $_error_msg = "ชื่อ username เป็นภาษาอังกฤษ ตัวเลข และสัญลักษณ์ . - _ เท่านั้น "; } if(strlen($_res_User)<6 || strlen($_res_User)>20){ $_error_msg = "ชื่อ username ต้องมีความยาว 6 - 20 ตัวอักษร"; } if(isset($_error_msg) && $_error_msg!=""){ $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); }else{ $sql=" SELECT member_id FROM tbl_member WHERE member_user = '".$_res_User."' "; $result = $mysqli->query($sql); if($result && $result->num_rows>0){ $_error_msg = "ชื่อ username นี้ถูกใช้งานแล้ว กรุณาใช้ชื่อใหม่"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); }else{ $sql2 = " INSERT INTO tbl_member SET member_user = '".$_res_User."' , member_pass = '".$_res_Pass."' , member_phone = '".$_res_Phone."' "; $result2 = $mysqli->query($sql2); if($result2 && $mysqli->affected_rows>0){ $_success_msg = "ทำการสมัครสมาชิกเรียบร้อยแล้ว"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg, "member_id" => $mysqli->insert_id, "member_user"=> $_res_User, "member_phone"=> $_res_Phone ); }else{ $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } } } // }elseif( isset($_POST['login_member']) && (isset($_POST['user']) && $_POST['user']!="") && (isset($_POST['pass']) && $_POST['pass']!="") ){ // กรณีตรวจสอบการล็อกอิน $_res_User = $mysqli->real_escape_string(trim($_POST['user'])); $_res_Pass = $mysqli->real_escape_string(trim($_POST['pass'])); if(strlen($_res_Pass)<4 || strlen($_res_User)>13){ $_error_msg = "รหัสผ่าน ต้องมีความยาว 4 - 13 ตัวอักษร"; } if(check_char($_res_User)==0){ $_error_msg = "ชื่อ username เป็นภาษาอังกฤษ ตัวเลข และสัญลักษณ์ . - _ เท่านั้น "; } if(strlen($_res_User)<6 || strlen($_res_User)>20){ $_error_msg = "ชื่อ username ต้องมีความยาว 6 - 20 ตัวอักษร"; } if(isset($_error_msg) && $_error_msg!=""){ $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); }else{ $sql=" SELECT member_id,member_user, member_phone FROM tbl_member WHERE member_user = '".$_res_User."' AND member_pass = '".$_res_Pass."' "; // echo $sql; $result = $mysqli->query($sql); if($result && $result->num_rows>0){ $row = $result->fetch_assoc(); $_success_msg = "ทำการล็อกอินเข้าสู่ระบบสำเร็จ"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg, "member_id" => $row['member_id'], "member_user"=> $row['member_user'], "member_phone"=> $row['member_phone'] ); }else{ $_error_msg = "ชื่อ username หรือ password ไม่ถูกต้อง กรุณาลองใหม่"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } } }elseif( isset($_POST['get_member']) && (isset($_POST['user']) && $_POST['user']!="") && (isset($_POST['id']) && $_POST['id']!="") ){ // กรณีเงื่อจไขการดึงข้อมูลในที่นี้เราจะใช้วิธีส่ง user กับ id $_res_User = $mysqli->real_escape_string(trim($_POST['user'])); $_res_ID = $mysqli->real_escape_string(trim($_POST['id'])); if(check_char($_res_User)==0){ $_error_msg = "ชื่อ username เป็นภาษาอังกฤษ ตัวเลข และสัญลักษณ์ . - _ เท่านั้น "; } if(strlen($_res_User)<6 || strlen($_res_User)>20){ $_error_msg = "ชื่อ username ต้องมีความยาว 6 - 20 ตัวอักษร"; } if(isset($_error_msg) && $_error_msg!=""){ $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); }else{ $sql=" SELECT member_id,member_user, member_phone FROM tbl_member WHERE member_user = '".$_res_User."' AND member_id = '".$_res_ID."' "; // echo $sql; $result = $mysqli->query($sql); if($result && $result->num_rows>0){ $row = $result->fetch_assoc(); $_success_msg = "ดาวน์โหลดข้อมูลเรียบร้อยแล้ว"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg, "member_id" => $row['member_id'], "member_user"=> $row['member_user'], "member_phone"=> $row['member_phone'] ); }else{ $_error_msg = "ไม่พบรายการข้อมูล"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } } }else{ // ถ้าไม่ได้กรอกข้อมลใดๆ เขามา $_error_msg = "โปรดกรอกข้อมูลให้ครบถ้วน"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } // แปลง array เป็นรูปแบบ json string if(isset($json_data)){ $json= json_encode($json_data); if(isset($_GET['callback']) && $_GET['callback']!=""){ echo $_GET['callback']."(".$json.");"; }else{ echo $json; } } ?>
สร้าง service เพื่อกำหนดคำสั่งทำงานต่าง ไว้เรียกใช้งานใน controller
ให้เปิดไฟล์ services.js ในโฟลเดอร์ js แล้วเพิ่มโค้ดดังนี้
'use strict'; angular.module('starter.services', []) .service('MemberService',function($http, $q){ // สร้าง service // กำหนด url ของ ไฟล์ api ของเรา var url = "http://192.168.8.102/app/api/member_api.php"; return { // ในที่นี้เราจะใช้การส่งค่าแบบ post ทั้งสามฟังก์ชั่น LoginMember: function($scope,dataSend) { var deferred = $q.defer(); $http.post(url,dataSend) .success(deferred.resolve) .error(deferred.reject); return deferred.promise; }, RegistMember: function($scope, dataSend) { var deferred = $q.defer(); $http.post(url, dataSend) .success(deferred.resolve) .error(deferred.reject); return deferred.promise; }, GetMember: function($scope, dataSend) { var deferred = $q.defer(); $http.post(url, dataSend) .success(deferred.resolve) .error(deferred.reject); return deferred.promise; } }; }) .service('ShareService',function(){ });
ก่อนที่เราจะไปต่อในส่วนของการทำงาน controller เราจะมีเช็คว่า plugin ที่จำเป็น
ได้ถูกติดตั้งไว้ครบแล้วหรือไม่่ เนื่องจากเราจะมีการส่งค่าไปยัง server ดังนั้น
app เขาเราต้องมี plugin ที่ตรวจสอบการเชื่อมต่อกับอินเทอร์เน็ตอยู่หรือไม่ก่อน
เพื่อแจ้งเตือนการส่งข้อมูล
ติดตั้ง plugin ที่ในการตรวจจับการเชื่อมต่อกับอินเทอร์เน็ต
ติดตั้ง plugin Network Information ด้วยคำสั่ง
C:\phonegap\learn002>cordova plugin add cordova-plugin-network-information
แต่โดยปกติ plugin ตัวนี้จะถูกติดตั้งมาเรียบร้อยแล้วเมื่อเรา build demo
อย่างไรก็ตามเพื่อให้มั่นควรทำการติดตั้งอีกครั้ง ซึ่งหากระบบพบว่าติดตั้งอยู่แล้ว ก็จะแจ้งอีกที
ต่อไปเป็นส่วนสำคัญ หรือก็คือส่วนของการกำหนด controller
ในส่วนของ controller ให้เปิดไฟล์ controllers.js ในโฟลเดอร์ js ขึ้นมา
แล้วปรับโค้ดให้เป็นดังนี้ (คำอธิบายแสดงในโค้ด หากมีอธิบายเพิ่มเติมจะแสดงด้านล่างโค้ด)
AppCtrl ส่วนของ controller หลัก
.controller('AppCtrl', function($scope, $ionicModal, $ionicPopover, $timeout, $ionicPopup,$ionicPlatform, $cordovaDialogs, $cordovaToast, $state ) { $scope.loginData = {}; $scope.isExpanded = false; $scope.hasHeaderFabLeft = false; $scope.hasHeaderFabRight = false; var navIcons = document.getElementsByClassName('ion-navicon'); for (var i = 0; i < navIcons.length; i++) { navIcons.addEventListener('click', function() { this.classList.toggle('active'); }); } //////////////////////////////////////// // Layout Methods //////////////////////////////////////// $scope.hideNavBar = function() { document.getElementsByTagName('ion-nav-bar')[0].style.display = 'none'; }; $scope.showNavBar = function() { document.getElementsByTagName('ion-nav-bar')[0].style.display = 'block'; }; $scope.noHeader = function() { var content = document.getElementsByTagName('ion-content'); for (var i = 0; i < content.length; i++) { if (content[i].classList.contains('has-header')) { content[i].classList.toggle('has-header'); } } }; $scope.setExpanded = function(bool) { $scope.isExpanded = bool; }; $scope.setHeaderFab = function(location) { var hasHeaderFabLeft = false; var hasHeaderFabRight = false; switch (location) { case 'left': hasHeaderFabLeft = true; break; case 'right': hasHeaderFabRight = true; break; } $scope.hasHeaderFabLeft = hasHeaderFabLeft; $scope.hasHeaderFabRight = hasHeaderFabRight; }; $scope.hasHeader = function() { var content = document.getElementsByTagName('ion-content'); for (var i = 0; i < content.length; i++) { if (!content[i].classList.contains('has-header')) { content[i].classList.toggle('has-header'); } } }; $scope.hideHeader = function() { $scope.hideNavBar(); $scope.noHeader(); }; $scope.showHeader = function() { $scope.showNavBar(); $scope.hasHeader(); }; $scope.clearFabs = function() { var fabs = document.getElementsByClassName('button-fab'); if (fabs.length && fabs.length > 1) { fabs[0].remove(); } }; $scope.noShadow = function() { var headerBar = document.getElementsByTagName('ion-header-bar'); for (var i = 0; i < headerBar.length; i++) { if (!headerBar[i].classList.contains('no-shadow')) { headerBar[i].classList.add('no-shadow'); } } }; $scope.hasShadow = function() { var headerBar = document.getElementsByTagName('ion-header-bar'); for (var i = 0; i < headerBar.length; i++) { if (headerBar[i].classList.contains('no-shadow')) { headerBar[i].classList.remove('no-shadow'); } } }; // ตัวแปรสำหรับกำหนด การซ่อนหรือแสดงเมนูสมาชิก false คือซ่อนเมนูสมาชิก $scope.showMemberMenu = false; // สร้างฟังก์ชั่น สำหรับเรียกใช้ เพื่อกำหนดการ กำหนดค่าตัวแปรเพื่อซ่อนหรือแสดงเมนู $scope.setMemberMenu = function(status){ $scope.showMemberMenu = status; }; // กำหนดตัวแปรไว้สำหรับเก็บ id ของสมาชิกที่สมัครในเครื่องนั้นๆ $scope.sesMemberID = null; // สร้างฟังก์ชั่นสำหรับกำหนดค่า id ให้สามารถเรียกใช้งานจาก $scope หลักได้ $scope.setMemberID = function(memID){ $scope.sesMemberID = memID; }; // สร้างฟังก์ชั่นสำหรับเรียกดูค่า id ของสมาชิกจาก $scope หลักได้ $scope.getMemberID = function(){ return $scope.sesMemberID; }; // กำหนดตัวแปรไว้สำหรับเก็บ username ของสมาชิกที่สมัครในเครื่องนั้นๆ $scope.sesMemberUser = null; // สร้างฟังก์ชั่นสำหรับกำหนดค่า username ให้สามารถเรียกใช้งานจาก $scope หลักได้ $scope.setMemberUser = function(memName){ $scope.sesMemberUser = memName; }; // สร้างฟังก์ชั่นสำหรับเรียกดูค่า username ของสมาชิกจาก $scope หลักได้ $scope.getMemberUser = function(){ return $scope.sesMemberUser; }; // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { // เชื่อมต่อ db สำเร็จ $scope.showToast('Open DB Success','long','bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เวลามีการทดสอบและเพิ่มฟิลด์หรือแก้ไขตารางควรเปิดคอมเม้นการลบตารางก่อน // นั้นหมายถึงตารางจะถูกสร้างและจัดรูปแบบใหม่ทุกครั้ง ข้อมูลตารางจะรีเซ็ต ล้างค่า // พอว่างโครงสร้างตารางเรียบร้อยแล้ว ให้ปิดคอมเม้นไว้เหมือนเดิม เพื่อให้ข้อมูลยังคงอยู่ // tx.executeSql('DROP TABLE IF EXISTS setting'); // ทำคำสั่งสร้างตาราง setting ถ้ายังไม่มี ในที่นี้เราเก็บแค่ setting_id และ member_id tx.executeSql('' + 'CREATE TABLE IF NOT EXISTS setting ' + '(setting_id integer primary key,' + 'member_id integer)' + ''); // เช็คตาราง setting ว่ามีข้อมูลไหม tx.executeSql("SELECT setting_id,member_id FROM setting ", [], function(tx, res) { if(res.rows.length<=0){ // ถ้าไม่มีข้อมูล ให้เพิ่มข้อมูลไป var query = "INSERT INTO setting" + " (member_id) " + " VALUES (?)"; var member_id = 0; // ทำงานคำสั่ง sql tx.executeSql(query, [member_id], function(tx, res) { // เมื่อทำการบันทึกข้อมูลสำเร็จ // ค่าเริ่มต้น เราจะให้ member_id เป็น 0 ไว้ก่อน แล้วค่อยมาอัพเเดทที่หลัง $scope.showToast('insertId: ' + res.insertId + ' -- probably 1','long','bottom'); $scope.showToast('rowsAffected: ' + res.rowsAffected + ' -- should be 1','long','bottom'); }, function(tx, error) { $scope.showToast('INSERT error: ' + error.message,'long','bottom'); }); }else{ // ถ้ามีข้อมูลอยู่แล้ว และ member_id ที่เก็บไว้ไม่เท่ากับ 0 if(res.rows.item(0).member_id!=0){ // เช็ค member_id ที่เก็ยไว้ไม่เท่ากับ 0 $scope.setMemberID(res.rows.item(0).member_id); // กำหนดค่าตัวแปร $state.go('app.profile'); // ไปที่หน้าโพรไฟล์ } } }); }, function (error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function () { $scope.showToast('transaction ok','long','bottom'); }); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างฟังก์ชั่นสำหรับ logout $scope.logoutMember = function(){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ขึ้นแจ้งเตือนว่าต้องการจะออกจากระบบหรือไม่ $cordovaDialogs.confirm('ยืนยันออกจากระบบ?', 'ออกจากระบบ?', ['ตกลง','ยกเลิก']) .then(function(buttonIndex) { // no button = 0, 'OK' = 1, 'Cancel' = 2 var btnIndex = buttonIndex; if(btnIndex==2){ // ถ้าตอบ ยกเลิก return false; // หยุดการทำงาน ไม่ต้องออกจากระบบ } if(btnIndex==1){ // ถ้าตอบ ตกลง ยืนบันออกจากรับบ // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // ล้างค่า member_id ที่บันทึกไว้ในตาราง setting ให้เป็น 0 คือไม่จำ member_id var query = "UPDATE setting SET member_id = 0 WHERE setting_id = 1"; tx.executeSql(query); $scope.sesMemberID = null; $scope.sesMemberUser = null; $state.go('app.login'); // ไปที่หน้าล็อกอิน }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); } }); }); }; })
ในส่วนของ controller หลัก เราจะมีการเก็บค่าตัวแปรเพิ่มเติมเข้ามาคือ $scope.sesMemberUser
เพื่อสำหรับเก็บ username ของสมาชิกไว้ใช้งานใน controller ต่างๆ ถ้าจำเป็น โดยมีการสร้างฟังก์ชั่น
ในการเรียกใช้ค่า และฟังก์ชั้นในการกำหนดค่า รวมถึงการล้างค่าถ้าสมาชิกล็อกเอาท์ออกจากระบบ
จะเห็นว่า เรายังคง รูปแบบการใช้งาน database อยู่แต่มีการปรับส่วนของการจัดเก็บข้อมูลของตาราง
member ใหม่
LoginCtrl ส่วนของ controller หน้า login
ในส่วนของล็อกอิน สิ่งที่เราจะมีการเรียกใช้เพิ่มเข้ามาคือ $cordovaNetwork, MemberService ,$rootScope โดยเราจะนำทั้งสามค่านี้เข้ามาใช้งานใน controller โดย
$cordovaNetwork เป็น plugin ตรวจสอบการเชื่อมต่อกับ อินเทอร์เน็ต
MemberService เป็น service ที่เราสร้างขึ้นในไฟล์ services.js สำหรับส่งค่าไปทำงานที่ฝั่ง server
MemberService เป็น service ที่เราสร้างขึ้นในไฟล์ services.js สำหรับส่งค่าไปทำงานที่ฝั่ง server
$rootScope เป็น root ของตัวแปร $scope ให้เราสามารถเรียกใช้งานใน controller อื่นๆ ที่ต้องการได้
.controller('LoginCtrl', function($scope, $timeout, $stateParams, ionicMaterialInk ,$ionicPlatform, $cordovaDialogs, $cordovaToast, $state, $cordovaNetwork, MemberService ,$rootScope) { $scope.$parent.clearFabs(); $scope.$parent.hasShadow(); $timeout(function() { $scope.$parent.hideHeader(); }, 0); // ตัวแปรสำหรับเก็บสถานะของ network $scope.network = { type:null, isOnline:null, isOffline:null }; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // https://github.com/apache/cordova-plugin-network-information $scope.network.type = $cordovaNetwork.getNetwork(); $scope.network.isOnline = $cordovaNetwork.isOnline(); $scope.network.isOffline = $cordovaNetwork.isOffline(); // เช็คว่าขณะนี้มือถือของเราเชื่อมต่อกับอินเทอร์เน็ตอยู่หรือไม่ $rootScope.$on('$cordovaNetwork:online', function(event, networkState){ $scope.network.isOffline = $cordovaNetwork.isOffline(); // จะได้ค่า $scope.network.isOffline เป็น false }); // เช็คว่าขณะนี้มือถือของเรา ไม่ได้เชื่อมต่อกับอินเทอร์เน็ตอยู่หรือไม่ $rootScope.$on('$cordovaNetwork:offline', function(event, networkState){ $scope.network.isOffline = $cordovaNetwork.isOffline(); // จะได้ค่า $scope.network.isOffline เป็น true }); }); // กำนหดค่าเริ่มต้นของฟอร์มหน้าสมัครสมาชิก ให้เป็นค่าว่าง $scope.login = { input_user:'', input_pass:'' }; // เรียกใช้ฟังก์ชั่นจาก AppCtrl หลัก เพื่อซ่อนเมนูสมาชิก โดยส่งค่า false เข้าไป $scope.$parent.setMemberMenu(false); // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { $scope.showToast('Open DB Success','long','bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เวลามีการทดสอบและเพิ่มฟิลด์หรือแก้ไขตารางควรเปิดคอมเม้นการลบตารางก่อน // นั้นหมายถึงตารางจะถูกสร้างและจัดรูปแบบใหม่ทุกครั้ง ข้อมูลตารางจะรีเซ็ต ล้างค่า // พอว่างโครงสร้างตารางเรียบร้อยแล้ว ให้ปิดคอมเม้นไว้เหมือนเดิม เพื่อให้ข้อมูลยังคงอยู่ // tx.executeSql('DROP TABLE IF EXISTS member'); // ทำคำสั่งสร้างตาราง member ถ้ายังไม่มี tx.executeSql('' + 'CREATE TABLE IF NOT EXISTS member ' + '(member_id integer,' + 'member_user text, ' + 'member_pass text,' + 'member_phone text)' + ''); // กำหนดให้ฟิลด์ member_id เป็น unique ไม่ซ้ำให้รองรับคำสั่ง REPLACE INTO tx.executeSql('CREATE UNIQUE INDEX IF NOT EXISTS idx_member_id ON member (member_id)'); }, function (error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function () { $scope.showToast('transaction ok','long','bottom'); }); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างฟังก์ชั่นสำหรับล็อกอิน รับค่า data จาก object login $scope.loginMember = function(data){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบถ้าไม่ได้เชื่อมต่อกับอินเทอร์เน็ต if($scope.network.isOffline==true){ $cordovaDialogs.alert('ไม่สามารถเชื่อมต่อกับเครือข่ายอินเทอร์เน็ตได้', 'เกิดข้อผิดพลาด', 'ตกลง') .then(function() { return false; }); return false; } // ตรวจสอบถ้ากรอกข้อมูลไม่ครบ if(data.input_user=="" || data.input_pass==""){ $cordovaDialogs.alert('โปรดกรอกข้อมูลให้ครบถ้วน', 'ข้อมูลจำเป็น', 'ตกลง') .then(function() { return false; }); return false; } // แสดงข้อมูลที่ส่งเข้ามา เวลาใช้จริงสามารถลบออกได้ $scope.showToast(' user: ' + data.input_user + ' pass: ' + data.input_pass +'', 'long', 'bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เตรียมข้อมูลสำหรับส่งไปใน service var dataSend = { login_member:1, user:data.input_user, pass:data.input_pass }; // service เรียกใช้ฟังก์ชั่น LoginMember ส่งค่าไปยัง server MemberService.LoginMember($scope, dataSend) .then(function(response) { if(response){ // ถ้าเกิดมีข้อความ error if(response[0].error!=null){ // ให้ขึ้นแจ้งเตือน $cordovaDialogs.alert(response[0].error, 'เกิดข้อผิดพลาด', 'ตกลง') .then(function() { return false; }); return false; } // ถ้าเกิดข้อความทำงานสำเร็จ if(response[0].success!=null){ // นำค่า ID และ username ที่ส่งกลับมา ของสมาชิกไปเก็บในตัวแปร sesMemberID // ที่อยู่ใน controller หลัก $scope.$parent.setMemberID(response[0].member_id); $scope.$parent.setMemberUser(response[0].member_user); // คำสั่ง sql สำหรับนำค่าที่ส่งกลับมาบันทึกทับเข้าไปใน databse ที่เครื่อง var query = "REPLACE INTO member" + " (member_id, member_user, member_pass, member_phone) " + " VALUES (?,?,?,?)"; // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { var dataSend = [ response[0].member_id, response[0].member_user, response[0].member_pass, response[0].member_phone ]; // ทำงานคำสั่ง sql tx.executeSql(query, dataSend, function(tx, res) { // เมื่อทำการบันทึกข้อมูลสำเร็จ // ใช้ค่า member_id จาก response[0].member_id แ $scope.$parent.setMemberID(response[0].member_id); $scope.showToast('insertId: ' + response[0].member_id+ ' -- probably 1','long','bottom'); // อัพเดท member_id เข้าไปในตาราง setting var query = "UPDATE setting SET member_id = ? WHERE setting_id = 1"; tx.executeSql(query, [response[0].member_id]); // ขึ้นแจ้ง เข้าสู่ระบบสำเร็จ และเปลี่ยนไปหน้า profile ด้วย $stat.go() $cordovaDialogs.alert(response[0].success, 'เข้าสู่ระบบ', 'ตกลง') .then(function() { $state.go('app.profile'); }); }, function(tx, error) { $scope.showToast('INSERT error: ' + error.message,'long','bottom'); }); }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); } } }); }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); }); }; ionicMaterialInk.displayEffect(); })
หลักการทำงานในหน้านี้ก็คือ เมือเข้ามาหน้าล็อกอิน ระบบจะเตรียม database ที่มีตารางให้พร้อม
สำหรับบันทึกข้อมูลสมาชิก เมือสมาชิกทำการกรอกข้อมูล แล้วกดล็อกอิน ระบบจะใช้ service ให้
ทำการส่งข้อมูลไปตรวจสอบที่ server จากนั้นก็ส่งค่ากลับมา หากสามารถล็อกอินได้ ระบบก็จะนำ
ค่าข้อมูลที่ส่งกลับมา มาบันทึกลงใน database ที่เครื่องอีกทีไว้เรียกใช้งาน หลังจากนั้นก็จะลิ้งคืไป
หน้าโพรไฟล์
RegistCtrl ส่วนของ controller หน้า register
ในส่วนของการสมัครสมาชิก หลักการทำงานจะคล้ายๆ กับหน้าล็อกอิน จะมีการเรียกใช้เพิ่มเข้ามาคือ
$cordovaNetwork, MemberService ,$rootScope โดยเราจะนำทั้งสามค่านี้เข้ามาใช้งานใน controller
.controller('RegistCtrl', function($scope, $timeout, $stateParams, ionicMaterialInk ,$ionicPlatform, $cordovaDialogs, $cordovaToast, $state, $cordovaNetwork, MemberService ,$rootScope) { $scope.$parent.clearFabs(); $scope.$parent.hasShadow(); $timeout(function() { $scope.$parent.hideHeader(); }, 0); // ตัวแปรสำหรับเก็บสถานะของ network $scope.network = { type:null, isOnline:null, isOffline:null }; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // https://github.com/apache/cordova-plugin-network-information $scope.network.type = $cordovaNetwork.getNetwork(); $scope.network.isOnline = $cordovaNetwork.isOnline(); $scope.network.isOffline = $cordovaNetwork.isOffline(); // เช็คว่าขณะนี้มือถือของเราเชื่อมต่อกับอินเทอร์เน็ตอยู่หรือไม่ $rootScope.$on('$cordovaNetwork:online', function(event, networkState){ $scope.network.isOffline = $cordovaNetwork.isOffline(); // จะได้ค่า $scope.network.isOffline เป็น false }); // เช็คว่าขณะนี้มือถือของเรา ไม่ได้เชื่อมต่อกับอินเทอร์เน็ตอยู่หรือไม่ $rootScope.$on('$cordovaNetwork:offline', function(event, networkState){ $scope.network.isOffline = $cordovaNetwork.isOffline(); // จะได้ค่า $scope.network.isOffline เป็น true }); }); // กำนหดค่าเริ่มต้นของฟอร์มหน้าสมัครสมาชิก ให้เป็นค่าว่าง $scope.reg = { input_user:'', input_pass:'', input_phone:'' }; // เรียกใช้ฟังก์ชั่นจาก AppCtrl หลัก เพื่อซ่อนเมนูสมาชิก โดยส่งค่า false เข้าไป $scope.$parent.setMemberMenu(false); // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { // เชื่อมต่อ db สำเร็จ $scope.showToast('Open DB Success','long','bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เวลามีการทดสอบและเพิ่มฟิลด์หรือแก้ไขตารางควรเปิดคอมเม้นการลบตารางก่อน // นั้นหมายถึงตารางจะถูกสร้างและจัดรูปแบบใหม่ทุกครั้ง ข้อมูลตารางจะรีเซ็ต ล้างค่า // พอว่างโครงสร้างตารางเรียบร้อยแล้ว ให้ปิดคอมเม้นไว้เหมือนเดิม เพื่อให้ข้อมูลยังคงอยู่ //tx.executeSql('DROP TABLE IF EXISTS member'); // ทำคำสั่งสร้างตาราง member ถ้ายังไม่มี tx.executeSql('' + 'CREATE TABLE IF NOT EXISTS member ' + '(member_id integer,' + 'member_user text, ' + 'member_pass text,' + 'member_phone text)' + ''); // กำหนดให้ฟิลด์ member_id เป็น unique ไม่ซ้ำให้รองรับคำสั่ง REPLACE INTO tx.executeSql('CREATE UNIQUE INDEX IF NOT EXISTS idx_member_id ON member (member_id)'); }, function (error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function () { $scope.showToast('transaction ok','long','bottom'); }); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างฟังก์ชั่นสำหรับสมัครสมาชิก รับค่า data จาก object reg $scope.registerMember = function(data){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบถ้าไม่ได้เชื่อมต่อกับอินเทอร์เน็ต if($scope.network.isOffline==true){ $cordovaDialogs.alert('ไม่สามารถเชื่อมต่อกับเครือข่ายอินเทอร์เน็ตได้', 'เกิดข้อผิดพลาด', 'ตกลง') .then(function() { return false; }); return false; } // ตรวจสอบให้กรอกข้อมูลให้ครบถ้วน if(data.input_user=="" || data.input_pass=="" || data.input_phone==""){ $cordovaDialogs.alert('โปรดกรอกข้อมูลให้ครบถ้วน', 'ข้อมูลจำเป็น', 'ตกลง') .then(function() { return false; }); return false; } // แสดงข้อมูลที่ส่งเข้ามา เวลาใช้จริงสามารถลบออกได้ $scope.showToast(' user: ' + data.input_user + ' pass: ' + data.input_pass + ' phone: ' + data.input_phone +'', 'long', 'bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เตรียมตัวแปรข้อมูลสำหรับส่งไปสมัครสมาชิกที่ server ด้วยฟังก์ชั่น RegistMember var dataSend = { new_member:1, user:data.input_user, pass:data.input_pass, phone:data.input_phone }; MemberService.RegistMember($scope, dataSend) .then(function(response) { if(response){ // ถ้าเกิดมีข้อความ error if(response[0].error!=null){ // ให้ขึ้นแจ้งเตือน $cordovaDialogs.alert(response[0].error, 'เกิดข้อผิดพลาด', 'ตกลง') .then(function() { return false; }); return false; } // ถ้าเกิดข้อความทำงานสำเร็จ if(response[0].success!=null){ // นำค่า ID และ username ที่ส่งกลับมา ของสมาชิกไปเก็บในตัวแปร sesMemberID // ที่อยู่ใน controller หลัก $scope.$parent.setMemberID(response[0].member_id); $scope.$parent.setMemberUser(response[0].member_user); var query = "INSERT INTO member" + " (member_id, member_user, member_pass, member_phone) " + " VALUES (?,?,?,?)"; db.transaction(function (tx) { var dataSend = [ response[0].member_id, response[0].member_user, response[0].member_pass, response[0].member_phone ]; // ทำงานคำสั่ง sql tx.executeSql(query, dataSend, function(tx, res) { // เมื่อทำการบันทึกข้อมูลสำเร็จ // ใช้ค่า member_id จาก response[0].member_id $scope.$parent.setMemberID(response[0].member_id); $scope.showToast('insertId: ' + response[0].member_id+ ' -- probably 1','long','bottom'); // อัพเดท member_id เข้าไปในตาราง setting var query = "UPDATE setting SET member_id = ? WHERE setting_id = 1"; tx.executeSql(query, [response[0].member_id]); // แจ้งการสมัครสมาชิกสำเร็จ และให้ไปที่หน้า profile $cordovaDialogs.alert(response[0].success, 'สมัครสมาชิกใหม่', 'ตกลง') .then(function() { $state.go('app.profile'); }); }, function(tx, error) { $scope.showToast('INSERT error: ' + error.message,'long','bottom'); }); }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); } } }); }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); }); }; ionicMaterialInk.displayEffect(); })
หลักการทำงานในหน้านี้ก็คือ เมือเข้ามาหน้าสมัครสมาชิก ระบบจะเตรียม database ที่มีตารางให้พร้อม สำหรับบันทึกข้อมูลสมาชิก
เมือสมาชิกทำการกรอกข้อมูล แล้วกดทำการสมัครสมาชิก ระบบจะใช้ service ให้ทำการส่งข้อมูลไปตรวจสอบที่ server และทำการบันทีกที่ฝั่ง server
เมือสมาชิกทำการกรอกข้อมูล แล้วกดทำการสมัครสมาชิก ระบบจะใช้ service ให้ทำการส่งข้อมูลไปตรวจสอบที่ server และทำการบันทีกที่ฝั่ง server
จากนั้นก็ส่งค่ากลับมา ระบบก็จะนำ ค่าข้อมูลที่ส่งกลับมา มาบันทึกลงใน database ที่เครื่องอีกที ไว้เรียกใช้งาน หลังจากนั้นก็จะลิ้งคืไปหน้าโพรไฟล์
ProfileCtrl ส่วนของ controller หน้า profile
ในส่วนของ ProfileCtrl เราจะยังใช้เป็นโค้ดเดิมไม่ได้แก้ไขเพิ่มเติมอะไร การทำงานก็จะยัง
คงเดิม คือไปดึงข้อมูลจาก database ที่เครื่องมาแสดง หากใครจะประยุกต์ให้ไปดึงข้อมูล
จาก server ก็สามารถทำได้ โดยดูจากตัวอย่างของ controller ล็อกอิน และ สมัครสมาชิก
ด้านบนเป็นแนวทางได้
.controller('ProfileCtrl', function( $scope, $stateParams, $timeout, ionicMaterialMotion, ionicMaterialInk, $ionicPlatform, $cordovaSpinnerDialog, $cordovaToast) { $scope.$parent.showHeader(); $scope.$parent.clearFabs(); $scope.isExpanded = false; $scope.$parent.setExpanded(false); $scope.$parent.setHeaderFab(false); $scope.$parent.hasShadow(); // กำหนดตัวแปรสำหรับค่าเริ่มต้นของข้อมูลหน้าโพรไลฟ์ $scope.member_user = ''; $scope.member_phone = ''; // กำหนดให้แสดงเมนูสมาชิ