เนื้อหาต่อไปนี้เป็นแนวทางสำหรับการสร้างหน้า app เพื่อใช้ในการตั้งค่าต่างๆ ในระบบ
app ของเรา ในที่นี้จะแสดงเฉพาะตัวอย่างการตั้งค่าการรับข้อความ push เป็นเนื้อหาที่เกี่ยว
เนื่องกับตอนที่แล้ว
ประยุกต์ใช้งาน Push Notification plugin ใน ionic metarial
https://www.ninenik.com/content.php?arti_id=749 via @ninenik
จากบทความที่ผ่านมา เราได้รู้โครงสร้างของ database บนฝั่ง server ว่ามีการเก็บฟิลด์
notify_status เก็บเป็นค่า 0 กับ 1
โดย 0 ให้หมายถึงผู้ใช้ app ไม่ต้องการรับข้อความ push และ 1 คือผู้ใช้ต้องการรับข้อความ push
เงื่อนไขนี้ ไว้ใช้สำหรับตอนที่ทำการดึงข้อมูลผู้ใช้ที่ต้องการรับข้อความ push โดยเพิ่มเงื่อนไข
WHERE notify_status = 1 เข้าไปในคำสั่ง SQL ตอนดึงข้อมูลฝั่ง server
ดังนั้นหน้าตั้งค่าการเปิดปิด push notification เราก็จะทำการส่งค่า 0 และ 1 มายัง server เพื่ออัพเดท
ฟิลด์ notify_status นอกจากนั้นเรายังจำเป็นจะต้องเก็บค่าสถานะการเปิดปิด push notification ไว้
ที่เครื่องด้วย เพื่อเป็นค่าเริ่มต้นในการแสดง และไม่ต้องเช็คไปยัง server ตอนเปิด app ขึ้นมา โดยการ
บันทึกไว้ที่เครื่องเราจะจัดเก็บใน database ผ่าน SQLite เก็บไว้ในตาราง setting
เนื้อหานี้จะเป็นการอธิบายโค้ด โดยโค้ดที่ทำรองรับไว้แล้ว สามารถดาวน์โหลดไฟล์ได้ที่บทความ
แจกตัวอย่างโค้ด ionic material รองรับการตั้งค่า Push Notifcation
https://www.ninenik.com/content.php?arti_id=750 via @ninenik
1. สร้าง Router กำหนด state ให้กับหน้า setting
เราได้รู้มาแล้วจากบทความก่อนๆ ว่าเมื่อมีการสร้างหน้า app ขึ้นมาใหม่จะมีการกำหนด state
ของหน้านั้นๆ ศึกษาเพิ่มเติมได้ที่
แนวทางการเพิ่มหน้า app และการจัด layout ใน ionic material
https://www.ninenik.com/content.php?arti_id=733 via @ninenik
ในส่วนนี้ให้เราเปิดไฟล์ app.js ในโฟลเดอร์ js ดูในส่วนของ method config()
เราได้มีการเพิ่ม state ของหน้า setting ดังนี้
.state('app.settings', {// กำหนด state
url: '/settings', // กำหนดตำแหน่งหน้า app คล้ายๆ url ในเว็บ
views: {
'menuContent': { // ส่วนของการแสดงใน view ชื่อ menuContent
templateUrl: 'templates/settings.html', // ใช้ template ชื่อ settings.html
controller: 'SettingCtrl'// กำหนดชื่อ controller ที่จะใช้งาน
},
'fabContent': { // ส่วนของการแสดงใน view ชื่อ fabContent ไม่ได้กำหนดอะไร
template: ''
}
}
})
จากรูปแบบการกำหนด state ให้กับหน้า setting สิ่งที่เราจะมีเพิ่มเข้ามาคือไฟล์ settings.html
และส่วนของการควบคุมหน้า setting ด้วยการกำหนด controller ที่ชื่อ SettingCtrl
โดยจะอธิบายสองส่วนนี้ใน ข้อที่ 3 และ 4 ตามลำดับ
2. เพิ่มฟิลด์ notify_status ใน database ของ SQLite
เนื่องจากเราจำเป็นต้องทำการเก็บค่า สถานะการรับข้อความ push ไว้ที่เครื่อง เราจะทำการ
เพิ่มฟิลด์ notify_status เข้าไปในตาราง (ปล. กรณีแก้ไขตาราง เวลาทดสอบ app ให้ทำการลบ
การติดตั้ง app เดิมก่อนเพื่อให้ระบบ reset โครงสร้างตารางใหม่ตอนติดตั้ง)
ให้ดูในส่วนของ AppCtrl ส่วนของ controller หลัก
โดยเปิดไฟล์ controllers.js ในโฟลเดอร์ js
.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;
};
// สร้างฟังก์ชั่นสำหรับเรียกใช้ 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,notify_status interger)' +
'');
// เช็คตาราง setting ว่ามีข้อมูลไหม
tx.executeSql(''+'SELECT setting_id,member_id,' +
'notify_status FROM setting', [], function(tx, res) {
if(res.rows.length<=0){ // ถ้าไม่มีข้อมูล ให้เพิ่มข้อมูลไป
var query = "INSERT INTO setting" +
" (member_id,notify_status) " +
" VALUES (?,1)";
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
$scope.setNotify(res.rows.item(0).notify_status);
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;
$state.go('app.login'); // ไปที่หน้าล็อกอิน
}, function(error) {
$scope.showToast('transaction error: ' + error.message,'long','bottom');
}, function() {
$scope.showToast('transaction ok','long','bottom');
});
}
});
});
};
// กำหนดตัวแปรไว้สำหรับเก็บ notify status ในเครื่องนั้นๆ
$scope.sesNotify = null;
// สร้างฟังก์ชั่นสำหรับกำหนดค่า notify status ให้สามารถเรียกใช้งานจาก $scope หลักได้
$scope.setNotify = function(status){
$scope.sesNotify = status;
};
// สร้างฟังก์ชั่นสำหรับเรียกดูค่า notify status ของสมาชิกจาก $scope หลักได้
$scope.getNotify = function(){
return $scope.sesNotify;
};
})
สังเกตให้ส่วนของคำสั่งสร้างตาราง
tx.executeSql('' +
'CREATE TABLE IF NOT EXISTS setting ' +
'(setting_id integer primary key,' +
'member_id integer,notify_status interger)' +
'');
เราได้เพิ่มฟิลด์ notify_status เก็บเป็น interger ไว้เก็บค่า 0 กับ 1
เมื่อสร้างตารางแล้ว เราจะให้ทำคำสั่ง ดึงข้อมูลในตาราง ในขั้นตอนนี้เราก็ต้อง
ดึงฟิลด์ notify_status ด้วย ตามคำสั่ง
tx.executeSql(''+'SELECT setting_id,member_id,' +
'notify_status FROM setting', [], function(tx, res) {
ปล. สังเกตคำสั่ง sql จะมีเป็นลักษณะการใช้การ + string ที่ขึ้นบรรทัดใหม่ ถ้าเขียนติดกันยาวๆ
จะได้เป็น
tx.executeSql('SELECT setting_id,member_id,notify_status FROM setting', [], function(tx, res) {
คำสั่งข้างต้น จะดึงค่ากรณีมีข้อมูล ไปใช้ในการแสดงหน้า setting ซึ่งถ้าเป็นการติดตั้ง app ครั้งแรก
ก็จะไมีมีข้อมูล ก็จะไปทำงานคำสั่งเพิ่มข้อมูล
var query = "INSERT INTO setting" +
" (member_id,notify_status) " +
" VALUES (?,1)";
var member_id = 0;
// ทำงานคำสั่ง sql
tx.executeSql(query, [member_id], function(tx, res) {
จะเห็นว่าในส่วนของการบันทึกข้อมูล เราจะส่งค่าแค่ค่าเดียวตัวตัวกำหนด ( ? )
tx.executeSql(query, [member_id], function(tx, res) {
คำสังนี้เราส่งแค่ member_id ส่วนค่า notify_status เรากำหนดค่าตายตัว ไปในคำสั่งแล้วเป็น 1
ข้างต้นเป็นกรณีไม่มีข้อมูล ส่วนกรณีมีข้อมูลในตารางแล้ว เราก็จะเข้าเงื่อนไข นำข้อมูล
ไปกำหนดค่า ผ่านฟังก์ชั่น
}else{ // ถ้ามีข้อมูลอยู่แล้ว และ member_id ที่เก็บไว้ไม่เท่ากับ 0
$scope.setNotify(res.rows.item(0).notify_status);
if(res.rows.item(0).member_id!=0){ // เช็ค member_id ที่เก็ยไว้ไม่เท่ากับ 0
$scope.setMemberID(res.rows.item(0).member_id); // กำหนดค่าตัวแปร
$state.go('app.profile'); // ไปที่หน้าโพรไฟล์
}
}
เงื่อนไขคือมีข้อมูลการตั้งค่า คำอธิบายด้านบนอธิบายผิด member_id เป็นค่าว่างก็ได้
บรรทัดต่อมาเราจะเห็นการใช้ฟังก์ชั่น เพื่อส่งค่าสถานะ notify_status ไปกำหนดในตัวแปร
// นำค่าจาก database ส่งค่าไปในฟังก์ชั่น กำหนดค่า sesNotify $scope.setNotify(res.rows.item(0).notify_status);
ค่าตัวแปร ฟังก์ชั่นกำหนดค่า และฟังก์ชั่นเรียกใช้ค่า เรากำหนดในส่วนของ AppCtrl ตามนี้
// กำหนดตัวแปรไว้สำหรับเก็บ notify status ในเครื่องนั้นๆ
$scope.sesNotify = null;
// สร้างฟังก์ชั่นสำหรับกำหนดค่า notify status ให้สามารถเรียกใช้งานจาก $scope หลักได้
$scope.setNotify = function(status){
$scope.sesNotify = status;
};
// สร้างฟังก์ชั่นสำหรับเรียกดูค่า notify status ของสมาชิกจาก $scope หลักได้
$scope.getNotify = function(){
return $scope.sesNotify;
};
3. สร้างหน้า setting สำหรับให้ผู้ใช้เปลี่ยนค่าสะานะการรับข้อความ push
ดูไฟล์ settings.html ในโฟลเดอร์ templates
<ion-view view-title="Settings">
<ion-nav-buttons side="right">
<div class="buttons buttons-right header-item">
<span class="right-buttons">
<button class="button button-icon button-clear ion-android-more-vertical"> </button>
</span>
</div>
</ion-nav-buttons>
<ion-content ng-class="{expanded:isExpanded}">
<div class="list">
<ion-toggle class="border-item"
ng-model="notify_status_checked"
ng-checked="notify_status_checked"
ng-change="changeNotiy()"
toggle-class="toggle-calm-900">
Push Notification
</ion-toggle>
</div>
<div class="padding">
{{notify_status_checked}}
</div>
</ion-content>
</ion-view>
สังเกตว่าเราใช้ directive ion-toggle ของ ionic (directive ก็คล้ายกับรูปแบบแท็กเฉพาะที่สร้างขึ้นมา แล้ว
จะถูกแปลงในรูปแบบแท็กพื้นฐาน html อีกที) ลักษณะ toggle ก็จะคล้าย checkbox หรือคล้ายกับ สวิชเปิดปิด
ng-model="notify_status_checked" คือ ค่าของ toggle ให้เท่ากับตัวแปร notify_status_checked ng-checked="notify_status_checked" คือ ค่าการเปิดปิด ให้เป็นไปตามค่าของตัวแปร notify_status_checked ng-change="changeNotiy()" คือ ถ้ามีการเปลี่ยนแปลงค่า ให้ไปทำงานฟังก์ชั่น changeNotify() toggle-class="toggle-calm-900" คือ ส่วนของการกำหนด css class
โดยค่าตัวแปร และฟังก์ชั่น เราจะเขียนไว้ในส่วนของการจัดการหรือ controller
จากโค้ดเรามีการแทรก คำสั่งการแสดงค่าตัวแปร เพื่อให้เห็นภาพ
<div class="padding">
{{notify_status_checked}}
</div>
4. จัดการการทำงานหน้า settng ใน SettingCtrl
ในไฟล์ controllers.js ในโฟลเดอร์ js ให้เราดูในส่วนของ SettingCtrl
หรือส่วนควบคุมการทำงาหน้า setting
.controller('SettingCtrl', function(
$scope, $stateParams, $timeout, ionicMaterialInk, ionicMaterialMotion
,$ionicPlatform, $cordovaToast, $cordovaDevice, notifyService) {
$scope.$parent.showHeader();
$scope.$parent.clearFabs();
$scope.$parent.setHeaderFab(false);
$scope.$parent.hasShadow();
$timeout(function() {
$scope.isExpanded = false;
$scope.$parent.setExpanded(false);
}, 300);
// สร้างฟังก์ชั่นสำหรับเรียกใช้ 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');
}, function (error) {
$scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom');
});
});
$scope.notify_status = $scope.$parent.getNotify();
$scope.notify_status_checked = ($scope.notify_status==1)?true:false;
$scope.changeNotiy = function(){
$ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin
// alert($scope.notify_status_checked);
var statusNotify = null;
var statusNotify_val = 0;
if ($scope.notify_status_checked == true) {
$scope.notify_status_checked = false;
// alert(0);
statusNotify_val = 0;
statusNotify = 'false';
} else {
$scope.notify_status_checked = true;
// alert(1);
statusNotify_val = 1;
statusNotify = 'true';
}
// เริ่มทำงานของคำสั่ง db
db.transaction(function (tx) {
// คำอธิบายในโค้ดตัวอย่างในไฟล์ที่แจก บรรทัดนี้ผิด ดูคำอธิบายด้านล่าง
var query = "UPDATE setting SET notify_status = ? WHERE setting_id = 1";
tx.executeSql(query, [statusNotify_val], function(tx, res) {
// เมื่อทำการบันทึกข้อมูลสำเร็จ
// เตรียมข้อมูลสำหรับส่งไปบันทึกบน server
$scope.$parent.setNotify(statusNotify_val);
var dataSend = {
uid: $cordovaDevice.getUUID(),
status: statusNotify
};
// service เรียกใช้ฟังก์ชั่น notifyService ส่งค่าไปยัง server
notifyService.updateNotify(dataSend)
.then(function (response) {
// ทดสอบแสดงค่าว่าบันทึกสำเร็จหรือไม่
// alert(JSON.stringify(response));
});
},
function(tx, error) {
$scope.showToast('Update error: ' + error.message,'long','bottom');
});
}, function (error) {
$scope.showToast('transaction error: ' + error.message, 'long', 'bottom');
}, function () {
$scope.showToast('transaction ok', 'long', 'bottom');
});
});
};
ionicMaterialMotion.fadeSlideInRight();
ionicMaterialInk.displayEffect();
})
จะเห็นว่าเรามีการ inject หรือเรียกใช้ $cordovaDevice และ notifyService
โดย $cordovaDevice เราจะใช้ดึงค่า UUID รหัสเฉพาะของเครื่องมือถือนั้น ส่งไปเช็ค
ค่าในตาราง tbl_notify บน server (เนื้อหาอ้างอิงบทความที่ผ่านมา เนื่องจากเรามีการ
เก็บค่า UUID และ registrandid สำหรับมือถือที่รับข้อความ push แต่เริ่มต้นแล้ว)
ส่วน nofityService เราจะเพิ่มฟังก์ชั่นการอัพเดทข้อมูลเข้าไป จากเดิม มีเพียงคำสั่งเพิ่มข้อมูล
ทำความเข้าใจในส่วน SettingCtrl ขออธิบายเฉพาะเนื้อหาใหม่
ส่วนแรก เราจะไปดึงค่าสถานะ จาก controller หลัก ผ่านฟังก์ชัน getNotify()
มาไว้ในตัวแปร notify_status ซึ่งกำหนดในรูปแบบ $scope.notify_status
สังเกตว่าการเรียกฟังชั่นจาก controller หลัก เราจะใช้ $scope.$parent. เพื่ออ้างอิง controller หลัก
แล้วตามด้วยฟังก์ชั่น ที่ต้องการ
$scope.notify_status = $scope.$parent.getNotify(); $scope.notify_status_checked = ($scope.notify_status==1)?true:false;
ส่วนต่อมาคือตัวแปรสถานะการเปิดปิด toggle จะใช้เป็น true หรือ false
โดยถ้าค่า $scope.notify_status==1 ให้ notify_status_checked เป็น true ถ้าเป็นอื่นให้มีค่าเป็น false
นั่นคือ ถ้าใน database มีการบันทึกเป้น 1 แล้ว ตัว toggle ในหน้า setting ก็จะแสดงเป็นสะานะเปิด ตาม
ค่าของตัวแปร notify_status_checked
ต่อไปมาดูส่วนของฟังก์ชั่น ขออธิบายในโค้ด
// เมื่อมีการเปลี่ยนค่า toggle
$scope.changeNotiy = function(){
$ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin
// ค่าที่ส่งเข้ามาของตัวแปร notify_status_checked จะเป็นค่าของสถานะก่อนเปลี่ยนค่า
// alert($scope.notify_status_checked);
var statusNotify = null; // สร้างตัวแปรเก็บสถานะแบบข้อความ
var statusNotify_val = 0; // สร้างตัวแปรเก็บถานะแบบตัวเลข
if ($scope.notify_status_checked == true) { // ค่าเดิมเป็น true เมื่อเปลี่ยน
$scope.notify_status_checked = false; // ให้กำหนดค่าหใม่เป็น false
// alert(0);
statusNotify_val = 0;
statusNotify = 'false';
} else { //เมื่อค่าเดิมเป็น false
$scope.notify_status_checked = true; // กำหนดค่าใหม่เป็น true
// alert(1);
statusNotify_val = 1;
statusNotify = 'true';
}
// เริ่มทำงานของคำสั่ง db
db.transaction(function (tx) {
// ทำคำสั่ง อัพเดทสถานะ notify_status ค่าที่อัพเดทเราจะใช้เป็นตัวแปรที่เก็บตัวเลข 0 หรือ 1
var query = "UPDATE setting SET notify_status = ? WHERE setting_id = 1";
tx.executeSql(query, [statusNotify_val], function(tx, res) {
// เมื่อทำการอัพเดทสำเร็จ
$scope.$parent.setNotify(statusNotify_val); // อัพเดทค่าในตัวแปรใน controller หลักด้วย
// เตรียมข้อมูลสำหรับส่งไปบันทึกบน server สัเกตสถาน เราจะส่งเป็นข้อความ ไปแทนโดยใช้
// เป็นข้อความ 'true' หรือ 'false'
var dataSend = {
uid: $cordovaDevice.getUUID(),
status: statusNotify
};
// service เรียกใช้ฟังก์ชั่น updateNotify จาก notifyService ส่งค่าไปยัง server
notifyService.updateNotify(dataSend)
.then(function (response) {
// ทดสอบแสดงค่าว่าบันทึกสำเร็จหรือไม่
// alert(JSON.stringify(response));
});
},
function(tx, error) {
$scope.showToast('Update error: ' + error.message,'long','bottom');
});
}, function (error) {
$scope.showToast('transaction error: ' + error.message, 'long', 'bottom');
}, function () {
$scope.showToast('transaction ok', 'long', 'bottom');
});
});
};
5. ส่วนของ service ที่เพิ่มฟังก์ชั่น อัพเดทข้อมูล
จากในข้อที่ 4 เรามีการใช้งาน notifyService ให้ทำงานต่อจากบันทึกข้อมูลลง database บนเครื่องแล้ว
ให้ทำงานอัพเดทสถานะบน server ด้วย ดูไฟล์ services.js ในโฟลเดอร์ js
.service('notifyService',function($http, $q){ // สร้าง service
// กำหนด url ของ ไฟล์ api ของเรา
var url = "http://192.168.8.100/app/api/notify_api.php";
return { // ในที่นี้เราจะใช้การส่งค่าแบบ post
setNotify: function(dataSend) {
var deferred = $q.defer();
$http.post(url,dataSend)
.success(deferred.resolve)
.error(deferred.reject);
return deferred.promise;
},
updateNotify: function(dataSend) {
var deferred = $q.defer();
$http.post(url,dataSend)
.success(deferred.resolve)
.error(deferred.reject);
return deferred.promise;
}
};
})
มีส่วนของฟังก์ชั่น updateNotify() เพิ่มเข้ามา ส่งค่าไปทำงานที่ไฟล์ notify_api.php ที่ฝั่ง server
โดยโค้ด notify_api.php เราก็เพิ่มในส่วนของเงื่อนไขการอัพเดทเข้าไปด้วย จะได้เป็น
ไฟล์ notify_api.php
<?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
}
$_error_msg = null;
$_success_msg = null;
if(
isset($_POST['regid']) && $_POST['regid']!="" &&
isset($_POST['uid']) && $_POST['uid']!=""
){ // ส่วนของเงื่อนไขเพิ่มข้อมูล
$_res_regID = $mysqli->real_escape_string(trim($_POST['regid']));
$_res_UID = $mysqli->real_escape_string(trim($_POST['uid']));
if(isset($_error_msg) && $_error_msg!=""){
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg
);
}else{
// เช็คในตารางก่อนว่า เครื่องมือถือนั้นๆ ได้เคยบันทึกข้อมูลมาก่อนแล้วหรือไม่ อิงจาก UUID
$sql="
SELECT notify_regid,notify_uid,notify_status FROM tbl_notify WHERE notify_uid = '".$_res_UID."'
";
$result = $mysqli->query($sql);
if($result && $result->num_rows>0){ // ถ้าเคยบันทึกแล้ว
$row = $result->fetch_assoc(); // ดึงค่ามาตรวจสอบ
$_success_msg=1;
if($row['notify_regid'] != $_res_regID){ // ถ้าค่าเดิม กับค่าหใม่ไม่เหมือนกัน ให้อัพเดทค่าใหม่
$sql2 = "
UPDATE tbl_notify SET
notify_regid = '".$_res_regID."' ,
notify_status = '1' ,
notify_updateadd = '".date('Y-m-d H:i:s')."'
WHERE notify_uid = '".$_res_UID."'
";
$result2 = $mysqli->query($sql2);
if($result2 && $mysqli->affected_rows>0){ // ถ้าอัพเดทสำเร็จ
$_success_msg=1;
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg,
"regid" => $_res_regID,
"uid"=> $_res_UID,
"status"=> 1
);
}else{ // ถ้าอัพเดทไม่สำเร็จ
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg
);
}
}else{ // ถ้าค่าใหม่ เท่ากับค่าเดิม ใช้ค่าเดิม
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg,
"regid" => $row['notify_regid'],
"uid" => $row['notify_uid'],
"status" => $row['notify_status']
);
}
}else{ // ถ้ายังไม่มีข้อมูล ให้บันทีกข้อมูลใหม่
$sql2 = "
INSERT INTO tbl_notify SET
notify_uid = '".$_res_UID."' ,
notify_regid = '".$_res_regID."' ,
notify_status = '1' ,
notify_dateadd = '".date('Y-m-d H:i:s')."'
";
$result2 = $mysqli->query($sql2);
if($result2 && $mysqli->affected_rows>0){ // ถ้าบันทึกขอ้มูลสำเร็จ
$_success_msg=1;
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg,
"regid" => $_res_regID,
"uid"=> $_res_UID,
"status"=> 1
);
}else{ // ถ้าบันทึกข้อมูลล้มเหลว
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg
);
}
}
}
//
}elseif(
isset($_POST['status']) && $_POST['status']!="" &&
isset($_POST['uid']) && $_POST['uid']!=""
){ // ส่วนของเงื่อนไขอัพเดทข้อมูล
$_res_STATUS = $mysqli->real_escape_string(trim($_POST['status']));
$_res_UID = $mysqli->real_escape_string(trim($_POST['uid']));
$_res_STATUS = ($_res_STATUS=='true')?1:0;
if(isset($_error_msg) && $_error_msg!=""){
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg
);
}else{
$sql="
SELECT notify_id,notify_regid FROM tbl_notify WHERE notify_uid = '".$_res_UID."'
";
$result = $mysqli->query($sql);
if($result && $result->num_rows>0){
$row = $result->fetch_assoc();
$_success_msg=1;
$sql2 = "
UPDATE tbl_notify SET
notify_status = '".$_res_STATUS."' ,
notify_updateadd = '".date('Y-m-d H:i:s')."'
WHERE notify_uid = '".$_res_UID."'
";
$result2 = $mysqli->query($sql2);
if($result2 && $mysqli->affected_rows>0){
$_success_msg=1;
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg,
"regid" => $row['notify_regid'],
"uid"=> $_res_UID,
"status"=> $_res_STATUS
);
}else{
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg
);
}
}else{
$sql2 = "
INSERT INTO tbl_notify SET
notify_uid = '".$_res_UID."' ,
notify_status = '".$_res_STATUS."' ,
notify_dateadd = '".date('Y-m-d H:i:s')."'
";
$result2 = $mysqli->query($sql2);
if($result2 && $mysqli->affected_rows>0){
$_success_msg=1;
$json_data[]=array(
"success" => $_success_msg,
"error" => $_error_msg,
"regid" => '',
"uid"=> $_res_UID,
"status"=> $_res_STATUS
);
}else{
$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;
}
}
?>
โดยในไฟล์ php เมื่อมีสถานะเป็นข้อความ เป็นคำว่า 'true' ส่งค่ามาอัพเดท ก็เปลี่ยนค่าเป้น 1
ถ้าเป็นอื่นเปลี่ยนค่าเป็น 0 แล้วบันทึกสถานะการรับข้อความ push ของผู้ใช้นั้นๆ
และในส่วนของการส่งข้อความ push เราก็เพิ่มเงื่อนไขตอนดึงข้อมูล ให้ดึงเฉพาะผู้ใช้ที่เปิดรับข้อความ
push ตัวอย่าง
ไฟล์ test_push.php ที่มีเงื่อนไข
<?php
header("Content-type:text/html; charset=UTF-8");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
// เชื่อมต่อกับฐานข้อมูล
require_once("dbconnect.php");
// ส่วนตั้งค่าการใช้งาน push
require_once("pusher.php");
$fcmToken = "your_fcm_token"; // ค่าา FCM token
$pusher = new Pusher($fcmToken);
$regId=array();
$sql="
SELECT * FROM tbl_notify WHERE notify_status = 1
";
$result = $mysqli->query($sql);
if($result){
while($row = $result->fetch_assoc()){
$regId[]=$row['notify_regid'];
}
}
$msg = array
(
'message' => 'ทดสอบข้อความภาษาไทย',
'title' => 'ทดสอบหัวข้อหลัก',
'subtitle' => 'ทดสอบหัวข้อย่อย',
'tickerText' => 'Ticker text here...Ticker text here...Ticker text here',
'vibrate' => 1,
'sound' => 1,
'count' => 2,
'image' => 'https://www.ninenik.com/images/banner_ninenik.gif',
'largeIcon' => 'large_icon',
'smallIcon' => 'small_icon'
);
$pusher->notify($regId, $msg);
echo "<pre>";
print_r($pusher->getOutputAsArray());
echo "</pre>";
?>
ทั้งหมดเป็นการอธิบายรูปแบบการทำงาน การกำหนดการตั้งค่าในหน้า setting สำหรับกำหนดสถานะ
push notification ให้ศึกษาเป็นแนวทางต่อไป